Unreachable code with Nothing-returning functions
This commit is contained in:
Generated
+1
@@ -2,6 +2,7 @@
|
||||
<dictionary name="abreslav">
|
||||
<words>
|
||||
<w>accessor</w>
|
||||
<w>dominator</w>
|
||||
<w>inferrer</w>
|
||||
<w>nondeterministic</w>
|
||||
<w>nullable</w>
|
||||
|
||||
@@ -265,9 +265,6 @@ public class JetControlFlowProcessor {
|
||||
builder.readUnit(expression);
|
||||
}
|
||||
builder.bindLabel(resultLabel);
|
||||
// if (!inCondition) {
|
||||
// builder.readNode(expression);
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -10,18 +10,50 @@ import java.util.Collection;
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface JetFlowInformationProvider {
|
||||
JetFlowInformationProvider ERROR = new JetFlowInformationProvider() {
|
||||
JetFlowInformationProvider THROW_EXCEPTION = new JetFlowInformationProvider() {
|
||||
@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();
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
};
|
||||
|
||||
void collectReturnedInformation(@NotNull JetElement subroutine, Collection<JetExpression> returnedExpressions, Collection<JetElement> elementsReturningUnit);
|
||||
void collectUnreachableExpressions(@NotNull JetElement subroutine, Collection<JetElement> unreachableElements);
|
||||
JetFlowInformationProvider NONE = new JetFlowInformationProvider() {
|
||||
@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
|
||||
*/
|
||||
public abstract class AbstractJumpInstruction extends Instruction {
|
||||
public abstract class AbstractJumpInstruction extends InstructionImpl {
|
||||
private final Label targetLabel;
|
||||
private Instruction resolvedTarget;
|
||||
|
||||
|
||||
@@ -1,31 +1,22 @@
|
||||
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 Instruction {
|
||||
private Collection<Instruction> previousInstructions = new LinkedHashSet<Instruction>();
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface Instruction {
|
||||
@NotNull
|
||||
Pseudocode getOwner();
|
||||
|
||||
public Collection<Instruction> getPreviousInstructions() {
|
||||
return previousInstructions;
|
||||
}
|
||||
void setOwner(@NotNull Pseudocode owner);
|
||||
|
||||
Collection<Instruction> getPreviousInstructions();
|
||||
|
||||
@NotNull
|
||||
public abstract Collection<Instruction> getNextInstructions();
|
||||
Collection<Instruction> getNextInstructions();
|
||||
|
||||
@Nullable
|
||||
protected Instruction outgoingEdgeTo(@Nullable Instruction target) {
|
||||
if (target != null) {
|
||||
target.getPreviousInstructions().add(this);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
public abstract void accept(InstructionVisitor visitor);
|
||||
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;
|
||||
}
|
||||
|
||||
private void add(Instruction instruction) {
|
||||
private void add(@NotNull Instruction instruction) {
|
||||
pseudocode.addInstruction(instruction);
|
||||
instruction.setOwner(pseudocode);
|
||||
if (instruction instanceof JetElementInstruction) {
|
||||
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
|
||||
trace.recordRepresentativeInstruction(elementInstruction.getElement(), instruction);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.jetbrains.jet.lang.psi.JetElement;
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface JetElementInstruction {
|
||||
public interface JetElementInstruction extends Instruction {
|
||||
@NotNull
|
||||
JetElement getElement();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.jetbrains.jet.lang.psi.JetElement;
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public abstract class JetElementInstructionImpl extends Instruction implements JetElementInstruction {
|
||||
public abstract class JetElementInstructionImpl extends InstructionImpl implements JetElementInstruction {
|
||||
protected final JetElement element;
|
||||
|
||||
public JetElementInstructionImpl(@NotNull JetElement element) {
|
||||
|
||||
@@ -13,12 +13,18 @@ public interface JetPseudocodeTrace {
|
||||
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
};
|
||||
|
||||
void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode);
|
||||
void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction);
|
||||
void close();
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.Collections;
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class SubroutineExitInstruction extends Instruction {
|
||||
public class SubroutineExitInstruction extends InstructionImpl {
|
||||
private final 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.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
@@ -20,4 +24,27 @@ public class JetPsiUtil {
|
||||
public static String safeName(String 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);
|
||||
|
||||
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<PsiElement, DeclarationDescriptor> declarationsToDescriptors = new HashMap<PsiElement, DeclarationDescriptor>();
|
||||
private final Set<JetFunctionLiteralExpression> blocks = new HashSet<JetFunctionLiteralExpression>();
|
||||
private final Set<JetElement> statements = new HashSet<JetElement>();
|
||||
|
||||
private JetScope toplevelScope;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -61,6 +63,11 @@ public class BindingTraceContext extends BindingTrace implements BindingContext
|
||||
blocks.add(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordStatement(@NotNull JetElement statement) {
|
||||
statements.add(statement);
|
||||
}
|
||||
|
||||
public void setToplevelScope(JetScope toplevelScope) {
|
||||
this.toplevelScope = toplevelScope;
|
||||
}
|
||||
@@ -135,4 +142,9 @@ public class BindingTraceContext extends BindingTrace implements BindingContext
|
||||
public boolean isBlock(JetFunctionLiteralExpression 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");
|
||||
} else {
|
||||
// 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 {
|
||||
type = typeResolver.resolveType(scope, propertyTypeRef);
|
||||
|
||||
@@ -96,7 +96,7 @@ public class TopDownAnalyzer {
|
||||
if (importDirective.isAllUnder()) {
|
||||
JetExpression importedReference = importDirective.getImportedReference();
|
||||
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) {
|
||||
namespaceScope.importScope(type.getMemberScope());
|
||||
}
|
||||
@@ -288,7 +288,7 @@ public class TopDownAnalyzer {
|
||||
flowInformationProvider.collectUnreachableExpressions(function, unreachableElements);
|
||||
|
||||
// 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 : 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) {
|
||||
final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration);
|
||||
final Map<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
|
||||
final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
|
||||
JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() {
|
||||
@Override
|
||||
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
||||
@@ -350,6 +329,12 @@ public class TopDownAnalyzer {
|
||||
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
|
||||
public void close() {
|
||||
pseudocodeTrace.close();
|
||||
@@ -363,7 +348,7 @@ public class TopDownAnalyzer {
|
||||
wrappedTrace.close();
|
||||
return new JetFlowInformationProvider() {
|
||||
@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);
|
||||
assert pseudocode != null;
|
||||
|
||||
@@ -372,7 +357,7 @@ public class TopDownAnalyzer {
|
||||
}
|
||||
|
||||
@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);
|
||||
assert pseudocode != null;
|
||||
|
||||
@@ -385,7 +370,38 @@ public class TopDownAnalyzer {
|
||||
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) {
|
||||
|
||||
}
|
||||
|
||||
@@ -250,7 +250,8 @@ public class JetStandardClasses {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -356,7 +356,9 @@ public class JetTypeInferrer {
|
||||
|
||||
JetType result = null;
|
||||
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?
|
||||
}
|
||||
return result;
|
||||
@@ -407,7 +409,11 @@ public class JetTypeInferrer {
|
||||
expression.accept(this);
|
||||
if (result != null) {
|
||||
trace.recordExpressionType(expression, result);
|
||||
if (JetStandardClasses.isNothing(result)) {
|
||||
markDominatedExpressionsAsUnreachable(expression);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -415,6 +421,18 @@ public class JetTypeInferrer {
|
||||
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
|
||||
@@ -488,7 +506,7 @@ public class JetTypeInferrer {
|
||||
}
|
||||
JetType effectiveReceiverType = receiverTypeRef == null ? null : receiverType;
|
||||
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
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
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.PsiManager;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.jet.lang.ErrorHandler;
|
||||
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.resolve.DescriptorUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JetQuickDocumentationProvider extends QuickDocumentationProvider {
|
||||
public class JetQuickDocumentationProvider implements DocumentationProvider {
|
||||
|
||||
@Override
|
||||
public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
|
||||
@@ -51,5 +55,23 @@ public class JetQuickDocumentationProvider extends QuickDocumentationProvider {
|
||||
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:
|
||||
<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 {
|
||||
<error>(return true) || (return false)</error>
|
||||
<error>1</error>
|
||||
<error>true</error>
|
||||
}
|
||||
|
||||
fun tf() {
|
||||
try {return} finally{return}
|
||||
try {<error>return</error>} finally{return}
|
||||
<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() {
|
||||
|
||||
@@ -459,14 +459,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
||||
private void assertType(String expression, JetType expectedType) {
|
||||
Project project = getProject();
|
||||
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));
|
||||
}
|
||||
|
||||
private void assertErrorType(String expression) {
|
||||
Project project = getProject();
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -489,7 +489,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
||||
private void assertType(JetScope scope, String expression, String expectedTypeStr) {
|
||||
Project project = getProject();
|
||||
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);
|
||||
assertEquals(expectedType, type);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user