Permalink
Browse files

KT-1175 Mark unused literals

  • Loading branch information...
svtk
svtk committed Jan 27, 2012
1 parent ca1abed commit 11ad28812d9fbb2785a8623e0f8baef18aa681cb
Showing with 183 additions and 89 deletions.
  1. +1 −1 compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java
  2. +33 −0 compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java
  3. +2 −0 compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java
  4. +54 −3 compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java
  5. +1 −1 compiler/frontend/src/org/jetbrains/jet/lang/psi/JetVisitorVoid.java
  6. +1 −1 compiler/frontend/src/org/jetbrains/jet/lang/psi/JetWhenConditionWithExpression.java
  7. +2 −0 compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java
  8. +1 −1 compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java
  9. +1 −1 compiler/testData/diagnostics/tests/FunctionReturnTypes.jet
  10. +24 −24 compiler/testData/diagnostics/tests/IncorrectCharacterLiterals.jet
  11. +12 −12 compiler/testData/diagnostics/tests/StringTemplates.jet
  12. +3 −3 compiler/testData/diagnostics/tests/UnreachableCode.jet
  13. +1 −1 compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.jet
  14. +3 −3 compiler/testData/diagnostics/tests/extensions/ExtensionFunctions.jet
  15. +4 −4 compiler/testData/diagnostics/tests/infos/Autocasts.jet
  16. +5 −5 compiler/testData/diagnostics/tests/regressions/kt306.jet
  17. +1 −1 compiler/testData/diagnostics/tests/regressions/kt402.jet
  18. +1 −1 compiler/testData/diagnostics/tests/regressions/kt41.jet
  19. +1 −1 compiler/testData/diagnostics/tests/regressions/kt847.jet
  20. +2 −2 compiler/testData/diagnostics/tests/shadowing/ShadowParameterInNestedBlockInFor.jet
  21. +3 −3 compiler/testData/diagnostics/tests/shadowing/ShadowVariableInNestedBlock.jet
  22. +2 −2 compiler/testData/diagnostics/tests/shadowing/ShadowVariableInNestedClosure.jet
  23. +2 −2 compiler/testData/diagnostics/tests/shadowing/ShadowVariableInNestedClosureParam.jet
  24. +2 −2 idea/testData/checker/ExtensionFunctions.jet
  25. +14 −12 idea/testData/checker/StringTemplates.jet
  26. +3 −3 idea/testData/checker/UnreachableCode.jet
  27. +4 −0 stdlib/ktSrc/Standard.kt
@@ -82,7 +82,7 @@ public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) {
}

@Override
public void visitWhenConditionExpression(JetWhenConditionWithExpression condition) {
public void visitWhenConditionWithExpression(JetWhenConditionWithExpression condition) {
JetExpressionPattern pattern = condition.getPattern();
if (pattern != null) {
pattern.accept(patternVisitor);
@@ -641,6 +641,39 @@ public VariableStatus merge(@Nullable VariableStatus variableStatus) {
}
}

////////////////////////////////////////////////////////////////////////////////
// "Unused literals" in block

public void markUnusedLiteralsInBlock(@NotNull JetElement subroutine) {
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null;
JetControlFlowGraphTraverser<Void> traverser = JetControlFlowGraphTraverser.create(pseudocode, true, true);
traverser.traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
@Override
public void execute(@NotNull Instruction instruction, @Nullable Void enterData, @Nullable Void exitData) {
if (!(instruction instanceof ReadValueInstruction)) return;
JetElement element = ((ReadValueInstruction) instruction).getElement();
if (!(element instanceof JetFunctionLiteralExpression
|| element instanceof JetConstantExpression
|| element instanceof JetStringTemplateExpression
|| element instanceof JetSimpleNameExpression)) {
return;
}
PsiElement parent = element.getParent();
if (parent instanceof JetBlockExpression) {
if (!JetPsiUtil.isImplicitlyUsed(element)) {
if (element instanceof JetFunctionLiteralExpression) {
trace.report(Errors.UNUSED_FUNCTION_LITERAL.on((JetFunctionLiteralExpression) element));
}
else {
trace.report(Errors.UNUSED_EXPRESSION.on(element));
}
}
}
}
});
}

////////////////////////////////////////////////////////////////////////////////
// Util methods 7

@@ -167,6 +167,8 @@ protected String makeMessageFor(JetElement argument) {
return argument.getText();
}
};
SimpleDiagnosticFactory UNUSED_EXPRESSION = SimpleDiagnosticFactory.create(WARNING, "The expression is unused");
SimplePsiElementOnlyDiagnosticFactory<JetFunctionLiteralExpression> UNUSED_FUNCTION_LITERAL = SimplePsiElementOnlyDiagnosticFactory.create(WARNING, "The function literal is unused. If you mean block, you can use 'run { ... }'");

PsiElementOnlyDiagnosticFactory1<JetExpression, DeclarationDescriptor> VAL_REASSIGNMENT = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Val can not be reassigned", NAME);
PsiElementOnlyDiagnosticFactory1<JetExpression, DeclarationDescriptor> INITIALIZATION_BEFORE_DECLARATION = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Variable cannot be initialized before declaration", NAME);
@@ -1,12 +1,14 @@
package org.jetbrains.jet.lang.psi;

import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lexer.JetTokens;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
@@ -85,11 +87,12 @@ public static String unquoteIdentifier(@NotNull String quoted) {

if (quoted.startsWith("`") && quoted.endsWith("`") && quoted.length() >= 2) {
return quoted.substring(1, quoted.length() - 1);
} else {
}
else {
return quoted;
}
}

@NotNull
public static String unquoteIdentifierOrFieldReference(@NotNull String quoted) {
if (quoted.indexOf('`') < 0) {
@@ -98,7 +101,8 @@ public static String unquoteIdentifierOrFieldReference(@NotNull String quoted) {

if (quoted.startsWith("$")) {
return "$" + unquoteIdentifier(quoted.substring(1));
} else {
}
else {
return unquoteIdentifier(quoted);
}
}
@@ -167,4 +171,51 @@ public static boolean isIrrefutable(JetWhenEntry entry) {
}
return false;
}

@Nullable
public static <T extends PsiElement> T getDirectParentOfTypeForBlock(@NotNull JetBlockExpression block, @NotNull Class<T> aClass) {
T parent = PsiTreeUtil.getParentOfType(block, aClass);
if (parent instanceof JetIfExpression) {
JetIfExpression ifExpression = (JetIfExpression) parent;
if (ifExpression.getElse() == block || ifExpression.getThen() == block) {
return parent;
}
}
if (parent instanceof JetWhenExpression) {
JetWhenExpression whenExpression = (JetWhenExpression) parent;
for (JetWhenEntry whenEntry : whenExpression.getEntries()) {
if (whenEntry.getExpression() == block) {
return parent;
}
}
}
if (parent instanceof JetFunctionLiteral) {
JetFunctionLiteral functionLiteral = (JetFunctionLiteral) parent;
if (functionLiteral.getBodyExpression() == block) {
return parent;
}
}
return null;
}

public static boolean isImplicitlyUsed(@NotNull JetElement element) {
PsiElement parent = element.getParent();
if (!(parent instanceof JetBlockExpression)) return true;
JetBlockExpression block = (JetBlockExpression) parent;
List<JetElement> statements = block.getStatements();
if (statements.get(statements.size() - 1) == element) {
JetExpression expression = getDirectParentOfTypeForBlock(block, JetIfExpression.class);
if (expression == null) {
expression = getDirectParentOfTypeForBlock(block, JetWhenExpression.class);
}
if (expression == null) {
expression = getDirectParentOfTypeForBlock(block, JetFunctionLiteral.class);
}
if (expression != null) {
return isImplicitlyUsed(expression);
}
}
return false;
}

}
@@ -358,7 +358,7 @@ public void visitWhenConditionInRange(JetWhenConditionInRange condition) {
visitJetElement(condition);
}

public void visitWhenConditionExpression(JetWhenConditionWithExpression condition) {
public void visitWhenConditionWithExpression(JetWhenConditionWithExpression condition) {
visitJetElement(condition);
}

@@ -20,7 +20,7 @@ public JetExpressionPattern getPattern() {

@Override
public void accept(@NotNull JetVisitorVoid visitor) {
visitor.visitWhenConditionExpression(this);
visitor.visitWhenConditionWithExpression(this);
}

@Override
@@ -81,5 +81,7 @@ private void checkFunction(JetDeclarationWithBody function, final @NotNull JetTy
flowInformationProvider.markUninitializedVariables(function.asElement(), context.isDeclaredLocally());

flowInformationProvider.markUnusedVariables(function.asElement());

flowInformationProvider.markUnusedLiteralsInBlock(function.asElement());
}
}
@@ -143,7 +143,7 @@ public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) {
}

@Override
public void visitWhenConditionExpression(JetWhenConditionWithExpression condition) {
public void visitWhenConditionWithExpression(JetWhenConditionWithExpression condition) {
JetPattern pattern = condition.getPattern();
if (pattern != null) {
newDataFlowInfo[0] = checkPatternType(pattern, subjectType, subjectExpression == null, scopeToExtend, context, subjectVariables);
@@ -36,7 +36,7 @@ fun intShortInfer() = 1
fun intShort() : Int = 1
//fun intBlockInfer() {1}
fun intBlock() : Int {return 1}
fun intBlock1() : Int {<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>1<!>}
fun intBlock1() : Int {<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY, UNUSED_EXPRESSION!>1<!>}

fun intString(): Int = <!TYPE_MISMATCH!>"s"<!>
fun intFunctionLiteral(): Int = <!TYPE_MISMATCH!>{ 10 }<!>
@@ -10,28 +10,28 @@ fun ff() {
}

fun test() {
'a'
'\n'
'\t'
'\b'
'\r'
'\"'
'\''
'\\'
'\$'
<!ERROR_COMPILE_TIME_VALUE!>'\x'<!>
<!ERROR_COMPILE_TIME_VALUE!>'\123'<!>
<!ERROR_COMPILE_TIME_VALUE!>'\ra'<!>
<!ERROR_COMPILE_TIME_VALUE!>'\000'<!>
<!ERROR_COMPILE_TIME_VALUE!>'\000'<!>
'\u0000'
'\u000a'
'\u000A'
<!ERROR_COMPILE_TIME_VALUE!>'\u'<!>
<!ERROR_COMPILE_TIME_VALUE!>'\u0'<!>
<!ERROR_COMPILE_TIME_VALUE!>'\u00'<!>
<!ERROR_COMPILE_TIME_VALUE!>'\u000'<!>
<!ERROR_COMPILE_TIME_VALUE!>'\u000z'<!>
<!ERROR_COMPILE_TIME_VALUE!>'\\u000'<!>
<!ERROR_COMPILE_TIME_VALUE!>'\'<!>
<!UNUSED_EXPRESSION!>'a'<!>
<!UNUSED_EXPRESSION!>'\n'<!>
<!UNUSED_EXPRESSION!>'\t'<!>
<!UNUSED_EXPRESSION!>'\b'<!>
<!UNUSED_EXPRESSION!>'\r'<!>
<!UNUSED_EXPRESSION!>'\"'<!>
<!UNUSED_EXPRESSION!>'\''<!>
<!UNUSED_EXPRESSION!>'\\'<!>
<!UNUSED_EXPRESSION!>'\$'<!>
<!ERROR_COMPILE_TIME_VALUE, UNUSED_EXPRESSION!>'\x'<!>
<!ERROR_COMPILE_TIME_VALUE, UNUSED_EXPRESSION!>'\123'<!>
<!ERROR_COMPILE_TIME_VALUE, UNUSED_EXPRESSION!>'\ra'<!>
<!ERROR_COMPILE_TIME_VALUE, UNUSED_EXPRESSION!>'\000'<!>
<!ERROR_COMPILE_TIME_VALUE, UNUSED_EXPRESSION!>'\000'<!>
<!UNUSED_EXPRESSION!>'\u0000'<!>
<!UNUSED_EXPRESSION!>'\u000a'<!>
<!UNUSED_EXPRESSION!>'\u000A'<!>
<!ERROR_COMPILE_TIME_VALUE, UNUSED_EXPRESSION!>'\u'<!>
<!ERROR_COMPILE_TIME_VALUE, UNUSED_EXPRESSION!>'\u0'<!>
<!ERROR_COMPILE_TIME_VALUE, UNUSED_EXPRESSION!>'\u00'<!>
<!ERROR_COMPILE_TIME_VALUE, UNUSED_EXPRESSION!>'\u000'<!>
<!ERROR_COMPILE_TIME_VALUE, UNUSED_EXPRESSION!>'\u000z'<!>
<!ERROR_COMPILE_TIME_VALUE, UNUSED_EXPRESSION!>'\\u000'<!>
<!ERROR_COMPILE_TIME_VALUE, UNUSED_EXPRESSION!>'\'<!>
}
@@ -7,16 +7,16 @@ fun demo() {
fun buzz(f : () -> Any?) : Int = 1
val sdf = 1
val foo = 3;
"$abc"
"$"
"$.$.asdf$\t"
"asd\$"
"asd$a<!ILLEGAL_ESCAPE_SEQUENCE!>\x<!>"
"asd$a$asd$ $<!UNRESOLVED_REFERENCE!>xxx<!>"
"fosdfasdo${1 + bar + 100}}sdsdfgdsfsdf"
"foo${bar + map {foo}}sdfsdf"
"foo${bar + map { "foo" }}sdfsdf"
"foo${bar + map {
"foo$sdf${ buzz{}}" }}sdfsdf"
"a<!ILLEGAL_ESCAPE_SEQUENCE!>\u<!> <!ILLEGAL_ESCAPE_SEQUENCE!>\u<!>0 <!ILLEGAL_ESCAPE_SEQUENCE!>\u<!>00 <!ILLEGAL_ESCAPE_SEQUENCE!>\u<!>000 \u0000 \u0AaA <!ILLEGAL_ESCAPE_SEQUENCE!>\u<!>0AAz.length( ) + \u0022b"
<!UNUSED_EXPRESSION!>"$abc"<!>
<!UNUSED_EXPRESSION!>"$"<!>
<!UNUSED_EXPRESSION!>"$.$.asdf$\t"<!>
<!UNUSED_EXPRESSION!>"asd\$"<!>
<!UNUSED_EXPRESSION!>"asd$a<!ILLEGAL_ESCAPE_SEQUENCE!>\x<!>"<!>
<!UNUSED_EXPRESSION!>"asd$a$asd$ $<!UNRESOLVED_REFERENCE!>xxx<!>"<!>
<!UNUSED_EXPRESSION!>"fosdfasdo${1 + bar + 100}}sdsdfgdsfsdf"<!>
<!UNUSED_EXPRESSION!>"foo${bar + map {foo}}sdfsdf"<!>
<!UNUSED_EXPRESSION!>"foo${bar + map { "foo" }}sdfsdf"<!>
<!UNUSED_EXPRESSION!>"foo${bar + map {
"foo$sdf${ buzz{}}" }}sdfsdf"<!>
<!UNUSED_EXPRESSION!>"a<!ILLEGAL_ESCAPE_SEQUENCE!>\u<!> <!ILLEGAL_ESCAPE_SEQUENCE!>\u<!>0 <!ILLEGAL_ESCAPE_SEQUENCE!>\u<!>00 <!ILLEGAL_ESCAPE_SEQUENCE!>\u<!>000 \u0000 \u0AaA <!ILLEGAL_ESCAPE_SEQUENCE!>\u<!>0AAz.length( ) + \u0022b"<!>
}
@@ -110,7 +110,7 @@ fun t7() : Int {
<!UNREACHABLE_CODE!>2<!>
}
catch (e : Any) {
2
<!UNUSED_EXPRESSION!>2<!>
}
return 1 // this is OK, like in Java
}
@@ -145,8 +145,8 @@ fun failtest(<!UNUSED_PARAMETER!>a<!> : Int) : Int {
}

fun foo(a : Nothing) : Unit {
1
a
<!UNUSED_EXPRESSION!>1<!>
<!UNUSED_EXPRESSION!>a<!>
<!UNREACHABLE_CODE!>2<!>
}

@@ -62,7 +62,7 @@ fun testCoercionToUnit() {
when(i) {
is 1 -> {
val d = 34
"1"
<!UNUSED_EXPRESSION!>"1"<!>
doSmth(d)

}
@@ -22,11 +22,11 @@ fun A.plus(<!UNUSED_PARAMETER!>a<!> : Any) {
1.foo()
true.<!NONE_APPLICABLE!>foo<!>()

1
<!UNUSED_EXPRESSION!>1<!>
}

fun A.plus(<!UNUSED_PARAMETER!>a<!> : Int) {
1
<!UNUSED_EXPRESSION!>1<!>
}

fun <T> T.minus(<!UNUSED_PARAMETER!>t<!> : T) : Int = 1
@@ -73,4 +73,4 @@ import outer.*
c<!UNNECESSARY_SAFE_CALL!>?.<!>equals2(null)

if (command == null) 1
}
}
@@ -116,12 +116,12 @@ fun f13(a : A?) {
}

if (!(a is val c is B) || !(a is val x is C)) {
<!UNRESOLVED_REFERENCE!>x<!>
<!UNRESOLVED_REFERENCE!>c<!>
<!UNRESOLVED_REFERENCE, UNUSED_EXPRESSION!>x<!>
<!UNRESOLVED_REFERENCE, UNUSED_EXPRESSION!>c<!>
}
else {
<!UNRESOLVED_REFERENCE!>x<!>
<!UNRESOLVED_REFERENCE!>c<!>
<!UNRESOLVED_REFERENCE, UNUSED_EXPRESSION!>x<!>
<!UNRESOLVED_REFERENCE, UNUSED_EXPRESSION!>c<!>
}

if (!(a is val c is B) || !(a is val c is C)) {
@@ -1,16 +1,16 @@
// KT-306 Ambiguity when different this's have same-looking functions

fun test() {
{Foo.() ->
<!UNUSED_FUNCTION_LITERAL!>{Foo.() ->
bar();
{Barr.() ->
this.bar()
bar()
}
}
{Barr.() ->
}<!>
<!UNUSED_FUNCTION_LITERAL!>{Barr.() ->
bar()
}
}<!>
}

class Foo {
@@ -19,4 +19,4 @@ class Foo {

class Barr {
fun bar() {}
}
}
@@ -1,7 +1,7 @@
package kt402

fun getTypeChecker() : (Any)->Boolean {
<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>{ (a : Any) -> a is <!UNRESOLVED_REFERENCE!>T<!> }<!> // reports unsupported
<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY, UNUSED_FUNCTION_LITERAL!>{ (a : Any) -> a is <!UNRESOLVED_REFERENCE!>T<!> }<!> // reports unsupported
}
fun f() : (Any) -> Boolean {
return { (a : Any) -> a is String }
@@ -7,5 +7,5 @@ fun aaa() =

fun bbb() {
aaa()
1 // Stupid error: unreachable code
<!UNUSED_EXPRESSION!>1<!> // Stupid error: unreachable code
}
@@ -1,3 +1,3 @@
fun <T> T.mustBe(t : T) {
"$this must be$<!SYNTAX!>as<!>$t"
<!UNUSED_EXPRESSION!>"$this must be$<!SYNTAX!>as<!>$t"<!>
}
Oops, something went wrong.

0 comments on commit 11ad288

Please sign in to comment.