Unreachable code with Nothing-returning functions
This commit is contained in:
Generated
+1
@@ -2,6 +2,7 @@
|
|||||||
<dictionary name="abreslav">
|
<dictionary name="abreslav">
|
||||||
<words>
|
<words>
|
||||||
<w>accessor</w>
|
<w>accessor</w>
|
||||||
|
<w>dominator</w>
|
||||||
<w>inferrer</w>
|
<w>inferrer</w>
|
||||||
<w>nondeterministic</w>
|
<w>nondeterministic</w>
|
||||||
<w>nullable</w>
|
<w>nullable</w>
|
||||||
|
|||||||
@@ -265,9 +265,6 @@ public class JetControlFlowProcessor {
|
|||||||
builder.readUnit(expression);
|
builder.readUnit(expression);
|
||||||
}
|
}
|
||||||
builder.bindLabel(resultLabel);
|
builder.bindLabel(resultLabel);
|
||||||
// if (!inCondition) {
|
|
||||||
// builder.readNode(expression);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -10,18 +10,50 @@ import java.util.Collection;
|
|||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public interface JetFlowInformationProvider {
|
public interface JetFlowInformationProvider {
|
||||||
JetFlowInformationProvider ERROR = new JetFlowInformationProvider() {
|
JetFlowInformationProvider THROW_EXCEPTION = new JetFlowInformationProvider() {
|
||||||
@Override
|
@Override
|
||||||
public void collectReturnedInformation(@NotNull JetElement subroutine, Collection<JetExpression> returnedExpressions, Collection<JetElement> elementsReturningUnit) {
|
public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void collectUnreachableExpressions(@NotNull JetElement subroutine, Collection<JetElement> unreachableElements) {
|
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void collectReturnedInformation(@NotNull JetElement subroutine, Collection<JetExpression> returnedExpressions, Collection<JetElement> elementsReturningUnit);
|
JetFlowInformationProvider NONE = new JetFlowInformationProvider() {
|
||||||
void collectUnreachableExpressions(@NotNull JetElement subroutine, Collection<JetElement> unreachableElements);
|
@Override
|
||||||
|
public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void collectReturnedInformation(
|
||||||
|
@NotNull JetElement subroutine,
|
||||||
|
@NotNull Collection<JetExpression> returnedExpressions,
|
||||||
|
@NotNull Collection<JetElement> elementsReturningUnit);
|
||||||
|
|
||||||
|
void collectUnreachableExpressions(
|
||||||
|
@NotNull JetElement subroutine,
|
||||||
|
@NotNull Collection<JetElement> unreachableElements);
|
||||||
|
|
||||||
|
void collectDominatedExpressions(
|
||||||
|
@NotNull JetExpression dominator,
|
||||||
|
@NotNull Collection<JetElement> dominated);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import java.util.Collections;
|
|||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractJumpInstruction extends Instruction {
|
public abstract class AbstractJumpInstruction extends InstructionImpl {
|
||||||
private final Label targetLabel;
|
private final Label targetLabel;
|
||||||
private Instruction resolvedTarget;
|
private Instruction resolvedTarget;
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,22 @@
|
|||||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public abstract class Instruction {
|
public interface Instruction {
|
||||||
private Collection<Instruction> previousInstructions = new LinkedHashSet<Instruction>();
|
@NotNull
|
||||||
|
Pseudocode getOwner();
|
||||||
|
|
||||||
public Collection<Instruction> getPreviousInstructions() {
|
void setOwner(@NotNull Pseudocode owner);
|
||||||
return previousInstructions;
|
|
||||||
}
|
Collection<Instruction> getPreviousInstructions();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public abstract Collection<Instruction> getNextInstructions();
|
Collection<Instruction> getNextInstructions();
|
||||||
|
|
||||||
@Nullable
|
void accept(InstructionVisitor visitor);
|
||||||
protected Instruction outgoingEdgeTo(@Nullable Instruction target) {
|
|
||||||
if (target != null) {
|
|
||||||
target.getPreviousInstructions().add(this);
|
|
||||||
}
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void accept(InstructionVisitor visitor);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public abstract class InstructionImpl implements Instruction {
|
||||||
|
private Pseudocode owner;
|
||||||
|
private final Collection<Instruction> previousInstructions = new LinkedHashSet<Instruction>();
|
||||||
|
|
||||||
|
protected InstructionImpl() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public Pseudocode getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOwner(@NotNull Pseudocode owner) {
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Instruction> getPreviousInstructions() {
|
||||||
|
return previousInstructions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected Instruction outgoingEdgeTo(@Nullable Instruction target) {
|
||||||
|
if (target != null) {
|
||||||
|
target.getPreviousInstructions().add(this);
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+6
-1
@@ -83,8 +83,13 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
return pseudocode;
|
return pseudocode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void add(Instruction instruction) {
|
private void add(@NotNull Instruction instruction) {
|
||||||
pseudocode.addInstruction(instruction);
|
pseudocode.addInstruction(instruction);
|
||||||
|
instruction.setOwner(pseudocode);
|
||||||
|
if (instruction instanceof JetElementInstruction) {
|
||||||
|
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
|
||||||
|
trace.recordRepresentativeInstruction(elementInstruction.getElement(), instruction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import org.jetbrains.jet.lang.psi.JetElement;
|
|||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public interface JetElementInstruction {
|
public interface JetElementInstruction extends Instruction {
|
||||||
@NotNull
|
@NotNull
|
||||||
JetElement getElement();
|
JetElement getElement();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import org.jetbrains.jet.lang.psi.JetElement;
|
|||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public abstract class JetElementInstructionImpl extends Instruction implements JetElementInstruction {
|
public abstract class JetElementInstructionImpl extends InstructionImpl implements JetElementInstruction {
|
||||||
protected final JetElement element;
|
protected final JetElement element;
|
||||||
|
|
||||||
public JetElementInstructionImpl(@NotNull JetElement element) {
|
public JetElementInstructionImpl(@NotNull JetElement element) {
|
||||||
|
|||||||
@@ -13,12 +13,18 @@ public interface JetPseudocodeTrace {
|
|||||||
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode);
|
void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode);
|
||||||
|
void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction);
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import java.util.Collections;
|
|||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public class SubroutineExitInstruction extends Instruction {
|
public class SubroutineExitInstruction extends InstructionImpl {
|
||||||
private final JetElement subroutine;
|
private final JetElement subroutine;
|
||||||
|
|
||||||
public SubroutineExitInstruction(@NotNull JetElement subroutine) {
|
public SubroutineExitInstruction(@NotNull JetElement subroutine) {
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ package org.jetbrains.jet.lang.psi;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
@@ -20,4 +24,27 @@ public class JetPsiUtil {
|
|||||||
public static String safeName(String name) {
|
public static String safeName(String name) {
|
||||||
return name == null ? "<no name provided>" : name;
|
return name == null ? "<no name provided>" : name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static Set<JetElement> findRootExpressions(@NotNull Collection<JetElement> unreachableElements) {
|
||||||
|
Set<JetElement> rootElements = new HashSet<JetElement>();
|
||||||
|
final Set<JetElement> shadowedElements = new HashSet<JetElement>();
|
||||||
|
JetVisitor shadowAllChildren = new JetVisitor() {
|
||||||
|
@Override
|
||||||
|
public void visitJetElement(JetElement elem) {
|
||||||
|
if (shadowedElements.add(elem)) {
|
||||||
|
elem.acceptChildren(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (JetElement element : unreachableElements) {
|
||||||
|
if (shadowedElements.contains(element)) continue;
|
||||||
|
element.acceptChildren(shadowAllChildren);
|
||||||
|
|
||||||
|
rootElements.removeAll(shadowedElements);
|
||||||
|
rootElements.add(element);
|
||||||
|
}
|
||||||
|
return rootElements;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,4 +27,5 @@ public interface BindingContext {
|
|||||||
PsiElement getDeclarationPsiElement(DeclarationDescriptor descriptor);
|
PsiElement getDeclarationPsiElement(DeclarationDescriptor descriptor);
|
||||||
|
|
||||||
boolean isBlock(JetFunctionLiteralExpression expression);
|
boolean isBlock(JetFunctionLiteralExpression expression);
|
||||||
|
boolean isStatement(JetExpression expression);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ public class BindingTraceContext extends BindingTrace implements BindingContext
|
|||||||
private final Map<DeclarationDescriptor, PsiElement> descriptorToDeclarations = new HashMap<DeclarationDescriptor, PsiElement>();
|
private final Map<DeclarationDescriptor, PsiElement> descriptorToDeclarations = new HashMap<DeclarationDescriptor, PsiElement>();
|
||||||
private final Map<PsiElement, DeclarationDescriptor> declarationsToDescriptors = new HashMap<PsiElement, DeclarationDescriptor>();
|
private final Map<PsiElement, DeclarationDescriptor> declarationsToDescriptors = new HashMap<PsiElement, DeclarationDescriptor>();
|
||||||
private final Set<JetFunctionLiteralExpression> blocks = new HashSet<JetFunctionLiteralExpression>();
|
private final Set<JetFunctionLiteralExpression> blocks = new HashSet<JetFunctionLiteralExpression>();
|
||||||
|
private final Set<JetElement> statements = new HashSet<JetElement>();
|
||||||
|
|
||||||
private JetScope toplevelScope;
|
private JetScope toplevelScope;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -61,6 +63,11 @@ public class BindingTraceContext extends BindingTrace implements BindingContext
|
|||||||
blocks.add(expression);
|
blocks.add(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recordStatement(@NotNull JetElement statement) {
|
||||||
|
statements.add(statement);
|
||||||
|
}
|
||||||
|
|
||||||
public void setToplevelScope(JetScope toplevelScope) {
|
public void setToplevelScope(JetScope toplevelScope) {
|
||||||
this.toplevelScope = toplevelScope;
|
this.toplevelScope = toplevelScope;
|
||||||
}
|
}
|
||||||
@@ -135,4 +142,9 @@ public class BindingTraceContext extends BindingTrace implements BindingContext
|
|||||||
public boolean isBlock(JetFunctionLiteralExpression expression) {
|
public boolean isBlock(JetFunctionLiteralExpression expression) {
|
||||||
return !expression.hasParameterSpecification() && blocks.contains(expression);
|
return !expression.hasParameterSpecification() && blocks.contains(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStatement(@NotNull JetExpression expression) {
|
||||||
|
return statements.contains(expression);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ public class ClassDescriptorResolver {
|
|||||||
type = ErrorUtils.createErrorType("No type, no body");
|
type = ErrorUtils.createErrorType("No type, no body");
|
||||||
} else {
|
} else {
|
||||||
// TODO : ??? Fix-point here: what if we have something like "val a = foo {a.bar()}"
|
// TODO : ??? Fix-point here: what if we have something like "val a = foo {a.bar()}"
|
||||||
type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.ERROR).getType(scope, initializer, false);
|
type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.THROW_EXCEPTION).getType(scope, initializer, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
type = typeResolver.resolveType(scope, propertyTypeRef);
|
type = typeResolver.resolveType(scope, propertyTypeRef);
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ public class TopDownAnalyzer {
|
|||||||
if (importDirective.isAllUnder()) {
|
if (importDirective.isAllUnder()) {
|
||||||
JetExpression importedReference = importDirective.getImportedReference();
|
JetExpression importedReference = importDirective.getImportedReference();
|
||||||
if (importedReference != null) {
|
if (importedReference != null) {
|
||||||
JetType type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.ERROR).getType(namespaceScope, importedReference, false);
|
JetType type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.THROW_EXCEPTION).getType(namespaceScope, importedReference, false);
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
namespaceScope.importScope(type.getMemberScope());
|
namespaceScope.importScope(type.getMemberScope());
|
||||||
}
|
}
|
||||||
@@ -288,7 +288,7 @@ public class TopDownAnalyzer {
|
|||||||
flowInformationProvider.collectUnreachableExpressions(function, unreachableElements);
|
flowInformationProvider.collectUnreachableExpressions(function, unreachableElements);
|
||||||
|
|
||||||
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
|
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
|
||||||
Set<JetElement> rootElements = findRootExpressions(unreachableElements);
|
Set<JetElement> rootElements = JetPsiUtil.findRootExpressions(unreachableElements);
|
||||||
|
|
||||||
// TODO : (return 1) || (return 2) -- only || and right of it is unreachable
|
// TODO : (return 1) || (return 2) -- only || and right of it is unreachable
|
||||||
// TODO : try {return 1} finally {return 2}. Currently 'return 1' is reported as unreachable,
|
// TODO : try {return 1} finally {return 2}. Currently 'return 1' is reported as unreachable,
|
||||||
@@ -318,31 +318,10 @@ public class TopDownAnalyzer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<JetElement> findRootExpressions(List<JetElement> unreachableElements) {
|
|
||||||
Set<JetElement> rootElements = new HashSet<JetElement>();
|
|
||||||
final Set<JetElement> shadowedElements = new HashSet<JetElement>();
|
|
||||||
JetVisitor shadowAllChildren = new JetVisitor() {
|
|
||||||
@Override
|
|
||||||
public void visitJetElement(JetElement elem) {
|
|
||||||
if (shadowedElements.add(elem)) {
|
|
||||||
elem.acceptChildren(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (JetElement element : unreachableElements) {
|
|
||||||
if (shadowedElements.contains(element)) continue;
|
|
||||||
element.acceptChildren(shadowAllChildren);
|
|
||||||
|
|
||||||
rootElements.removeAll(shadowedElements);
|
|
||||||
rootElements.add(element);
|
|
||||||
}
|
|
||||||
return rootElements;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JetFlowInformationProvider computeFlowData(@NotNull JetDeclaration declaration, @NotNull JetExpression bodyExpression) {
|
private JetFlowInformationProvider computeFlowData(@NotNull JetDeclaration declaration, @NotNull JetExpression bodyExpression) {
|
||||||
final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration);
|
final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration);
|
||||||
final Map<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
|
final Map<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
|
||||||
|
final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
|
||||||
JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() {
|
JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() {
|
||||||
@Override
|
@Override
|
||||||
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
||||||
@@ -350,6 +329,12 @@ public class TopDownAnalyzer {
|
|||||||
pseudocodeMap.put(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();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
pseudocodeTrace.close();
|
pseudocodeTrace.close();
|
||||||
@@ -363,7 +348,7 @@ public class TopDownAnalyzer {
|
|||||||
wrappedTrace.close();
|
wrappedTrace.close();
|
||||||
return new JetFlowInformationProvider() {
|
return new JetFlowInformationProvider() {
|
||||||
@Override
|
@Override
|
||||||
public void collectReturnedInformation(@NotNull JetElement subroutine, Collection<JetExpression> returnedExpressions, Collection<JetElement> elementsReturningUnit) {
|
public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
|
||||||
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||||
assert pseudocode != null;
|
assert pseudocode != null;
|
||||||
|
|
||||||
@@ -372,7 +357,7 @@ public class TopDownAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void collectUnreachableExpressions(@NotNull JetElement subroutine, Collection<JetElement> unreachableElements) {
|
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
|
||||||
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||||
assert pseudocode != null;
|
assert pseudocode != null;
|
||||||
|
|
||||||
@@ -385,7 +370,38 @@ public class TopDownAnalyzer {
|
|||||||
unreachableElements.add(((JetElementInstruction) instruction).getElement());
|
unreachableElements.add(((JetElementInstruction) instruction).getElement());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
|
||||||
|
Instruction dominatorInstruction = representativeInstructions.get(dominator);
|
||||||
|
if (dominatorInstruction == null) {
|
||||||
|
// assert
|
||||||
|
// dominator instanceof JetContinueExpression ||
|
||||||
|
// dominator instanceof JetBreakExpression ||
|
||||||
|
// dominator instanceof JetReturnExpression ||
|
||||||
|
// dominator instanceof JetBlockExpression ||
|
||||||
|
// dominator instanceof JetFunctionLiteralExpression
|
||||||
|
// : "No representative instruction for a Nothing-typed expression: " + dominator.getText();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction();
|
||||||
|
|
||||||
|
Set<Instruction> reachable = new HashSet<Instruction>();
|
||||||
|
collectReachable(enterInstruction, reachable);
|
||||||
|
|
||||||
|
Set<Instruction> reachableWithDominatorProhibited = new HashSet<Instruction>();
|
||||||
|
reachableWithDominatorProhibited.add(dominatorInstruction);
|
||||||
|
collectReachable(enterInstruction, reachableWithDominatorProhibited);
|
||||||
|
|
||||||
|
for (Instruction instruction : reachable) {
|
||||||
|
if (instruction instanceof JetElementInstruction
|
||||||
|
&& reachable.contains(instruction)
|
||||||
|
&& !reachableWithDominatorProhibited.contains(instruction)) {
|
||||||
|
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
|
||||||
|
dominated.add(elementInstruction.getElement());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ public class BindingTrace {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void recordStatement(@NotNull JetElement statement) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public void removeReferenceResolution(@NotNull JetReferenceExpression referenceExpression) {
|
public void removeReferenceResolution(@NotNull JetReferenceExpression referenceExpression) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,7 +250,8 @@ public class JetStandardClasses {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isNothing(@NotNull JetType type) {
|
public static boolean isNothing(@NotNull JetType type) {
|
||||||
return type.getConstructor() == NOTHING_CLASS.getTypeConstructor();
|
return !(type instanceof NamespaceType) &&
|
||||||
|
type.getConstructor() == NOTHING_CLASS.getTypeConstructor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JetType getTupleType(List<Attribute> attributes, List<JetType> arguments) {
|
public static JetType getTupleType(List<Attribute> attributes, List<JetType> arguments) {
|
||||||
|
|||||||
@@ -356,7 +356,9 @@ public class JetTypeInferrer {
|
|||||||
|
|
||||||
JetType result = null;
|
JetType result = null;
|
||||||
for (JetElement statement : block) {
|
for (JetElement statement : block) {
|
||||||
result = blockLevelVisitor.getType((JetExpression) statement);
|
trace.recordStatement(statement);
|
||||||
|
JetExpression statementExpression = (JetExpression) statement;
|
||||||
|
result = blockLevelVisitor.getType(statementExpression);
|
||||||
blockLevelVisitor.resetResult(); // TODO : maybe it's better to recreate the visitors with the same scope?
|
blockLevelVisitor.resetResult(); // TODO : maybe it's better to recreate the visitors with the same scope?
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -407,7 +409,11 @@ public class JetTypeInferrer {
|
|||||||
expression.accept(this);
|
expression.accept(this);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
trace.recordExpressionType(expression, result);
|
trace.recordExpressionType(expression, result);
|
||||||
|
if (JetStandardClasses.isNothing(result)) {
|
||||||
|
markDominatedExpressionsAsUnreachable(expression);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,6 +421,18 @@ public class JetTypeInferrer {
|
|||||||
result = null;
|
result = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private void markDominatedExpressionsAsUnreachable(JetExpression expression) {
|
||||||
|
List<JetElement> dominated = new ArrayList<JetElement>();
|
||||||
|
flowInformationProvider.collectDominatedExpressions(expression, dominated);
|
||||||
|
Set<JetElement> rootExpressions = JetPsiUtil.findRootExpressions(dominated);
|
||||||
|
for (JetElement rootExpression : rootExpressions) {
|
||||||
|
semanticServices.getErrorHandler().genericError(rootExpression.getNode(),
|
||||||
|
"This code is unreachable, because '" + expression.getText() + "' never terminates normally");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -488,7 +506,7 @@ public class JetTypeInferrer {
|
|||||||
}
|
}
|
||||||
JetType effectiveReceiverType = receiverTypeRef == null ? null : receiverType;
|
JetType effectiveReceiverType = receiverTypeRef == null ? null : receiverType;
|
||||||
JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
|
JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
|
||||||
result = JetStandardClasses.getFunctionType(null, effectiveReceiverType, parameterTypes, safeReturnType);
|
result = JetStandardClasses.getFunctionType(Collections.<Attribute>emptyList(), effectiveReceiverType, parameterTypes, safeReturnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
package org.jetbrains.jet.plugin;
|
package org.jetbrains.jet.plugin;
|
||||||
|
|
||||||
import com.intellij.lang.documentation.QuickDocumentationProvider;
|
import com.intellij.lang.documentation.DocumentationProvider;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiManager;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import org.jetbrains.jet.lang.ErrorHandler;
|
import org.jetbrains.jet.lang.ErrorHandler;
|
||||||
import org.jetbrains.jet.lang.psi.JetFile;
|
import org.jetbrains.jet.lang.psi.JetFile;
|
||||||
@@ -11,10 +12,13 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
|
|||||||
import org.jetbrains.jet.lang.types.DeclarationDescriptor;
|
import org.jetbrains.jet.lang.types.DeclarationDescriptor;
|
||||||
import org.jetbrains.jet.resolve.DescriptorUtil;
|
import org.jetbrains.jet.resolve.DescriptorUtil;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public class JetQuickDocumentationProvider extends QuickDocumentationProvider {
|
public class JetQuickDocumentationProvider implements DocumentationProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
|
public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
|
||||||
@@ -51,5 +55,23 @@ public class JetQuickDocumentationProvider extends QuickDocumentationProvider {
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getUrlFor(PsiElement element, PsiElement originalElement) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generateDoc(PsiElement element, PsiElement originalElement) {
|
||||||
|
return "<no doc>";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PsiElement getDocumentationElementForLookupItem(PsiManager psiManager, Object object, PsiElement element) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PsiElement getDocumentationElementForLink(PsiManager psiManager, String link, PsiElement context) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -435,3 +435,26 @@ l3:
|
|||||||
l1:
|
l1:
|
||||||
<END>
|
<END>
|
||||||
=====================
|
=====================
|
||||||
|
== tf ==
|
||||||
|
fun tf() {
|
||||||
|
try {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
---------------------
|
||||||
|
l0:
|
||||||
|
<START>
|
||||||
|
jmp?(l2)
|
||||||
|
r(1)
|
||||||
|
r(2)
|
||||||
|
ret(*) l1
|
||||||
|
ret(*) l1
|
||||||
|
l2:
|
||||||
|
r(2)
|
||||||
|
ret(*) l1
|
||||||
|
l1:
|
||||||
|
<END>
|
||||||
|
=====================
|
||||||
|
|||||||
@@ -127,10 +127,10 @@ fun t8() {
|
|||||||
|
|
||||||
fun blockAndAndMismatch() : Boolean {
|
fun blockAndAndMismatch() : Boolean {
|
||||||
<error>(return true) || (return false)</error>
|
<error>(return true) || (return false)</error>
|
||||||
<error>1</error>
|
<error>true</error>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tf() {
|
fun tf() {
|
||||||
try {return} finally{return}
|
try {<error>return</error>} finally{return}
|
||||||
<error>1</error>
|
<error>1</error>
|
||||||
}
|
}
|
||||||
@@ -56,6 +56,10 @@ public class JetControlFlowTest extends JetTestCaseBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) {
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
AnalyzingUtils.analyzeNamespace(file.getRootNamespace(), ErrorHandler.DO_NOTHING, new JetControlFlowDataTraceFactory() {
|
AnalyzingUtils.analyzeNamespace(file.getRootNamespace(), ErrorHandler.DO_NOTHING, new JetControlFlowDataTraceFactory() {
|
||||||
|
|||||||
@@ -459,14 +459,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
|||||||
private void assertType(String expression, JetType expectedType) {
|
private void assertType(String expression, JetType expectedType) {
|
||||||
Project project = getProject();
|
Project project = getProject();
|
||||||
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
|
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
|
||||||
JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.ERROR).getType(classDefinitions.BASIC_SCOPE, jetExpression, false);
|
JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.NONE).getType(classDefinitions.BASIC_SCOPE, jetExpression, false);
|
||||||
assertTrue(type + " != " + expectedType, JetTypeImpl.equalTypes(type, expectedType));
|
assertTrue(type + " != " + expectedType, JetTypeImpl.equalTypes(type, expectedType));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertErrorType(String expression) {
|
private void assertErrorType(String expression) {
|
||||||
Project project = getProject();
|
Project project = getProject();
|
||||||
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
|
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
|
||||||
JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.ERROR).safeGetType(classDefinitions.BASIC_SCOPE, jetExpression, false);
|
JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.NONE).safeGetType(classDefinitions.BASIC_SCOPE, jetExpression, false);
|
||||||
assertTrue("Error type expected but " + type + " returned", ErrorUtils.isErrorType(type));
|
assertTrue("Error type expected but " + type + " returned", ErrorUtils.isErrorType(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,7 +489,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
|||||||
private void assertType(JetScope scope, String expression, String expectedTypeStr) {
|
private void assertType(JetScope scope, String expression, String expectedTypeStr) {
|
||||||
Project project = getProject();
|
Project project = getProject();
|
||||||
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
|
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
|
||||||
JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.ERROR).getType(scope, jetExpression, false);
|
JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.NONE).getType(scope, jetExpression, false);
|
||||||
JetType expectedType = expectedTypeStr == null ? null : makeType(expectedTypeStr);
|
JetType expectedType = expectedTypeStr == null ? null : makeType(expectedTypeStr);
|
||||||
assertEquals(expectedType, type);
|
assertEquals(expectedType, type);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user