Refactoring: checkType && checkImplicitCast returned to DataFlowUtils, PROCESSED unboxing returned, StringTemplateVisitor made local

This commit is contained in:
Mikhail Glukhikh
2015-04-23 14:00:08 +03:00
parent 8b241b8c05
commit 525b9e63ae
9 changed files with 78 additions and 66 deletions
@@ -157,8 +157,9 @@ public class BindingContextUtils {
@Nullable
public static JetTypeInfo getRecordedTypeInfo(@NotNull JetExpression expression, @NotNull BindingContext context) {
// noinspection ConstantConditions
if (!context.get(BindingContext.PROCESSED, expression)) return null;
// NB: should never return null if expression is already processed
if (!Boolean.TRUE.equals(context.get(BindingContext.PROCESSED, expression))) return null;
JetTypeInfo result = context.get(BindingContext.EXPRESSION_TYPE_INFO, expression);
return result != null ? result : TypeInfoFactoryPackage.noTypeInfo(DataFlowInfo.EMPTY);
}
@@ -104,7 +104,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
// TODO : type substitutions???
CallExpressionResolver callExpressionResolver = components.expressionTypingServices.getCallExpressionResolver();
JetTypeInfo typeInfo = callExpressionResolver.getSimpleNameExpressionTypeInfo(expression, NO_RECEIVER, null, context);
return typeInfo.checkType(expression, context); // TODO : Extensions to this
return DataFlowUtils.checkType(typeInfo, expression, context); // TODO : Extensions to this
}
@Override
@@ -158,7 +158,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
JetTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType.replaceExpectedType(targetType));
checkBinaryWithTypeRHS(expression, context, targetType, typeInfo.getType());
return typeInfo.replaceType(targetType).checkType(expression, context);
return DataFlowUtils.checkType(typeInfo.replaceType(targetType), expression, context);
}
JetTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType);
@@ -176,7 +176,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
JetType result = operationType == AS_SAFE ? TypeUtils.makeNullable(targetType) : targetType;
return typeInfo.replaceType(result).checkType(expression, context);
return DataFlowUtils.checkType(typeInfo.replaceType(result), expression, context);
}
private void checkBinaryWithTypeRHS(
@@ -582,7 +582,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
});
result[0] = defaultType;
if (Boolean.FALSE.equals(context.trace.get(PROCESSED, expression))) {
// noinspection ConstantConditions
if (!context.trace.get(PROCESSED, expression)) {
temporaryTrace.recordType(expression, defaultType);
temporaryTrace.record(PROCESSED, expression);
}
@@ -887,7 +888,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
return createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType);
}
return typeInfo.replaceType(result).checkType(expression, contextWithExpectedType);
return DataFlowUtils.checkType(typeInfo.replaceType(result), expression, contextWithExpectedType);
}
@NotNull
@@ -936,7 +937,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
// The call to checkType() is only needed here to execute additionalTypeCheckers, hence the NO_EXPECTED_TYPE
return baseTypeInfo.replaceType(resultingType).checkType(expression, context.replaceExpectedType(NO_EXPECTED_TYPE));
return DataFlowUtils.checkType(baseTypeInfo.replaceType(resultingType), expression, context.replaceExpectedType(NO_EXPECTED_TYPE));
}
@Override
@@ -1087,7 +1088,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (value != null) {
return createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType);
}
return result.checkType(expression, contextWithExpectedType);
return DataFlowUtils.checkType(result, expression, contextWithExpectedType);
}
private JetTypeInfo visitEquality(
@@ -1357,7 +1358,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@Override
public JetTypeInfo visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression, ExpressionTypingContext context) {
return resolveArrayAccessGetMethod(expression, context).checkType(expression, context);
return DataFlowUtils.checkType(resolveArrayAccessGetMethod(expression, context), expression, context);
}
@NotNull
@@ -1409,45 +1410,37 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
return TypeInfoFactoryPackage.noTypeInfo(context);
}
private class StringTemplateVisitor extends JetVisitorVoid {
final ExpressionTypingContext context;
JetTypeInfo typeInfo;
StringTemplateVisitor(ExpressionTypingContext context) {
this.context = context;
this.typeInfo = TypeInfoFactoryPackage.noTypeInfo(context);
}
@Override
public void visitStringTemplateEntryWithExpression(@NotNull JetStringTemplateEntryWithExpression entry) {
JetExpression entryExpression = entry.getExpression();
if (entryExpression != null) {
typeInfo = facade.getTypeInfo(entryExpression, context.replaceDataFlowInfo(typeInfo.getDataFlowInfo()));
}
}
@Override
public void visitEscapeStringTemplateEntry(@NotNull JetEscapeStringTemplateEntry entry) {
CompileTimeConstantChecker.CharacterWithDiagnostic value = CompileTimeConstantChecker.escapedStringToCharacter(entry.getText(), entry);
Diagnostic diagnostic = value.getDiagnostic();
if (diagnostic != null) {
context.trace.report(diagnostic);
}
}
}
@Override
public JetTypeInfo visitStringTemplateExpression(@NotNull JetStringTemplateExpression expression, ExpressionTypingContext contextWithExpectedType) {
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
StringTemplateVisitor visitor = new StringTemplateVisitor(context);
final ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
class StringTemplateVisitor extends JetVisitorVoid {
private JetTypeInfo typeInfo = TypeInfoFactoryPackage.noTypeInfo(context);
@Override
public void visitStringTemplateEntryWithExpression(@NotNull JetStringTemplateEntryWithExpression entry) {
JetExpression entryExpression = entry.getExpression();
if (entryExpression != null) {
typeInfo = facade.getTypeInfo(entryExpression, context.replaceDataFlowInfo(typeInfo.getDataFlowInfo()));
}
}
@Override
public void visitEscapeStringTemplateEntry(@NotNull JetEscapeStringTemplateEntry entry) {
CompileTimeConstantChecker.CharacterWithDiagnostic value = CompileTimeConstantChecker.escapedStringToCharacter(entry.getText(), entry);
Diagnostic diagnostic = value.getDiagnostic();
if (diagnostic != null) {
context.trace.report(diagnostic);
}
}
}
StringTemplateVisitor visitor = new StringTemplateVisitor();
for (JetStringTemplateEntry entry : expression.getEntries()) {
entry.accept(visitor);
}
ConstantExpressionEvaluator.evaluate(expression, context.trace, contextWithExpectedType.expectedType);
return visitor.typeInfo.replaceType(components.builtIns.getStringType()).checkType(expression, contextWithExpectedType);
return DataFlowUtils.checkType(visitor.typeInfo.replaceType(components.builtIns.getStringType()),
expression,
contextWithExpectedType);
}
@Override
@@ -189,8 +189,12 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
} else {
dataFlowInfo = typeInfo.getDataFlowInfo().or(otherInfo);
}
return typeInfo.replaceType(components.builtIns.getUnitType()).checkType(ifExpression, context).
checkImplicitCast(ifExpression, context, isStatement).replaceDataFlowInfo(dataFlowInfo);
return DataFlowUtils.checkImplicitCast(DataFlowUtils.checkType(typeInfo.replaceType(components.builtIns.getUnitType()),
ifExpression,
context),
ifExpression,
context,
isStatement).replaceDataFlowInfo(dataFlowInfo);
}
@Override
@@ -240,8 +244,9 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
// but without affecting changing variables
dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo()));
}
return bodyTypeInfo.replaceType(components.builtIns.getUnitType()).checkType(expression, contextWithExpectedType).replaceDataFlowInfo(
dataFlowInfo);
return DataFlowUtils
.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType)
.replaceDataFlowInfo(dataFlowInfo);
}
private boolean containsJumpOutOfLoop(final JetLoopExpression loopExpression, final ExpressionTypingContext context) {
@@ -337,13 +342,16 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
// Here we must record data flow information at the end of the body (or at the first jump, to be precise) and
// .and it with entrance data flow information, because do-while body is executed at least once
// See KT-6283
// NB: it's really important to do it for non-empty body which is not a function literal
// If it's a function literal, it appears always unused so it's no matter what we do at this point
if (body != null) {
// We should take data flow info from the first jump point,
// but without affecting changing variables
dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo()));
}
return bodyTypeInfo.replaceType(components.builtIns.getUnitType()).checkType(expression, contextWithExpectedType).replaceDataFlowInfo(
dataFlowInfo);
return DataFlowUtils
.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType)
.replaceDataFlowInfo(dataFlowInfo);
}
@Override
@@ -402,8 +410,9 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
bodyTypeInfo = loopRangeInfo;
}
return bodyTypeInfo.replaceType(components.builtIns.getUnitType()).checkType(expression, contextWithExpectedType).replaceDataFlowInfo(
loopRangeInfo.getDataFlowInfo());
return DataFlowUtils
.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType)
.replaceDataFlowInfo(loopRangeInfo.getDataFlowInfo());
}
private VariableDescriptor createLoopParameterDescriptor(
@@ -149,6 +149,11 @@ public class DataFlowUtils {
return checkType(expressionType, expression, context, null);
}
@NotNull
public static JetTypeInfo checkType(@NotNull JetTypeInfo typeInfo, @NotNull JetExpression expression, @NotNull ResolutionContext context) {
return typeInfo.replaceType(checkType(typeInfo.getType(), expression, context));
}
@Nullable
public static JetType checkType(
@Nullable JetType expressionType,
@@ -220,6 +225,11 @@ public class DataFlowUtils {
return expressionType;
}
@NotNull
public static JetTypeInfo checkImplicitCast(@NotNull JetTypeInfo typeInfo, @NotNull JetExpression expression, @NotNull ResolutionContext context, boolean isStatement) {
return typeInfo.replaceType(checkImplicitCast(typeInfo.getType(), expression, context, isStatement));
}
@NotNull
public static JetTypeInfo illegalStatementType(@NotNull JetExpression expression, @NotNull ExpressionTypingContext context, @NotNull ExpressionTypingInternals facade) {
facade.checkStatementType(
@@ -228,7 +228,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
else {
return facade.getTypeInfo(expression, context);
}
return result.checkType(expression, context);
return DataFlowUtils.checkType(result, expression, context);
}
@NotNull
@@ -42,12 +42,6 @@ import org.jetbrains.kotlin.types.JetType
fun clearType() = replaceType(null)
fun checkType(expression: JetExpression, context: ResolutionContext<*>) =
replaceType(DataFlowUtils.checkType(type, expression, context))
fun checkImplicitCast(expression: JetExpression, context: ResolutionContext<*>, isStatement: Boolean) =
replaceType(DataFlowUtils.checkImplicitCast(type, expression, context, isStatement))
// NB: do not compare type with this.type because this comparison is complex and unstabld
fun replaceType(type: JetType?) = JetTypeInfo(type, dataFlowInfo, jumpOutPossible, jumpFlowInfo)
@@ -57,10 +51,12 @@ import org.jetbrains.kotlin.types.JetType
fun replaceJumpFlowInfo(jumpFlowInfo: DataFlowInfo) =
if (jumpFlowInfo == this.jumpFlowInfo) this else JetTypeInfo(type, dataFlowInfo, jumpOutPossible, jumpFlowInfo)
fun replaceDataFlowInfo(dataFlowInfo: DataFlowInfo) =
if (dataFlowInfo == this.dataFlowInfo) this
// If jump flow information was the same, it should be changed together
else if (this.dataFlowInfo == jumpFlowInfo) JetTypeInfo(type, dataFlowInfo, jumpOutPossible, dataFlowInfo)
// Otherwise they are changed separately
else JetTypeInfo(type, dataFlowInfo, jumpOutPossible, jumpFlowInfo)
fun replaceDataFlowInfo(dataFlowInfo: DataFlowInfo) = when (this.dataFlowInfo) {
// Nothing changed
dataFlowInfo -> this
// Jump info is the same as data flow info: change both
jumpFlowInfo -> JetTypeInfo(type, dataFlowInfo, jumpOutPossible, dataFlowInfo)
// Jump info is not the same: change data flow info only
else -> JetTypeInfo(type, dataFlowInfo, jumpOutPossible, jumpFlowInfo)
}
}
@@ -63,7 +63,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
DataFlowInfo newDataFlowInfo = conditionInfo.and(typeInfo.getDataFlowInfo());
context.trace.record(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression, newDataFlowInfo);
}
return typeInfo.replaceType(KotlinBuiltIns.getInstance().getBooleanType()).checkType(expression, contextWithExpectedType);
return DataFlowUtils.checkType(typeInfo.replaceType(KotlinBuiltIns.getInstance().getBooleanType()), expression, contextWithExpectedType);
}
@Override
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.expressions.DataFlowUtils
import org.jetbrains.kotlin.types.expressions.JetTypeInfo
/*
@@ -40,4 +41,4 @@ public fun noTypeInfo(dataFlowInfo: DataFlowInfo): JetTypeInfo = createTypeInfo(
public fun noTypeInfo(context: ResolutionContext<*>): JetTypeInfo = noTypeInfo(context.dataFlowInfo)
public fun createCheckedTypeInfo(type: JetType?, context: ResolutionContext<*>, expression: JetExpression): JetTypeInfo =
createTypeInfo(type, context).checkType(expression, context)
DataFlowUtils.checkType(createTypeInfo(type, context), expression, context)
@@ -3,7 +3,9 @@ fun bar(): Boolean { return true }
public fun foo(x: String?): Int {
var y: Any
do {
y = ""
// This and hashCode() below are needed just to prevent
// UNINITIALIZED_VARIABLE, UNUSED_VALUE, ...
y = ""
y = if (x == null) break else <!DEBUG_INFO_SMARTCAST!>x<!>
} while (bar())
y.hashCode()