Ignore data flow info from assert calls
if assertions mode is not LEGACY. This is done since assertions can be disabled (in both compile time and runtime) and thus, the data flow info is not reliable anymore. #KT-24529: Fixed
This commit is contained in:
+3
-13
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.cli.common.arguments
|
||||
@@ -259,6 +248,7 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||
supportCompatqualCheckerFrameworkAnnotations
|
||||
)
|
||||
result[AnalysisFlag.enableJvmDefault] = enableJvmDefault
|
||||
result[AnalysisFlag.ignoreDataFlowInAssert] = JVMAssertionsMode.fromString(assertionsMode) != JVMAssertionsMode.LEGACY
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
@@ -17,5 +17,8 @@ enum class JVMAssertionsMode(val description: String) {
|
||||
|
||||
@JvmStatic
|
||||
fun fromStringOrNull(string: String?) = values().find { it.description == string }
|
||||
|
||||
@JvmStatic
|
||||
fun fromString(string: String?) = fromStringOrNull(string) ?: DEFAULT
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.FunctionTypesKt;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.config.AnalysisFlag;
|
||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
@@ -655,6 +656,7 @@ public class CallResolver {
|
||||
@NotNull ResolutionTask<D> resolutionTask,
|
||||
@NotNull TracingStrategy tracing
|
||||
) {
|
||||
DataFlowInfo initialInfo = context.dataFlowInfoForArguments.getResultInfo();
|
||||
if (context.checkArguments == CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS) {
|
||||
argumentTypeResolver.analyzeArgumentsAndRecordTypes(context, ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS);
|
||||
}
|
||||
@@ -673,14 +675,32 @@ public class CallResolver {
|
||||
}
|
||||
}
|
||||
|
||||
OverloadResolutionResultsImpl<D> result;
|
||||
if (!(resolutionTask.resolutionKind instanceof NewResolutionOldInference.ResolutionKind.GivenCandidates)) {
|
||||
assert resolutionTask.name != null;
|
||||
return newResolutionOldInference.runResolution(context, resolutionTask.name, resolutionTask.resolutionKind, tracing);
|
||||
result = newResolutionOldInference.runResolution(context, resolutionTask.name, resolutionTask.resolutionKind, tracing);
|
||||
}
|
||||
else {
|
||||
assert resolutionTask.givenCandidates != null;
|
||||
return newResolutionOldInference.runResolutionForGivenCandidates(context, tracing, resolutionTask.givenCandidates);
|
||||
result = newResolutionOldInference.runResolutionForGivenCandidates(context, tracing, resolutionTask.givenCandidates);
|
||||
}
|
||||
|
||||
// in code like
|
||||
// assert(a!!.isEmpty())
|
||||
// a.length
|
||||
// we should ignore data flow info from assert argument, since assertions can be disabled and
|
||||
// thus it will lead to NPE in runtime otherwise
|
||||
if (languageVersionSettings.getFlag(AnalysisFlag.getIgnoreDataFlowInAssert()) && result.isSingleResult()) {
|
||||
D descriptor = result.getResultingDescriptor();
|
||||
if (descriptor.getName().equals(Name.identifier("assert"))) {
|
||||
DeclarationDescriptor declaration = descriptor.getContainingDeclaration();
|
||||
if (declaration instanceof PackageFragmentDescriptor &&
|
||||
((PackageFragmentDescriptor) declaration).getFqName().asString().equals("kotlin")) {
|
||||
context.dataFlowInfoForArguments.updateInfo(context.call.getValueArguments().get(0), initialInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// !IGNORE_DATA_FLOW_IN_ASSERT
|
||||
// SKIP_TXT
|
||||
// WITH_RUNTIME
|
||||
|
||||
interface A {}
|
||||
|
||||
class B: A {
|
||||
fun bool() = true
|
||||
}
|
||||
|
||||
fun test1(a: A) {
|
||||
assert((a as B).bool())
|
||||
a.<!UNRESOLVED_REFERENCE!>bool<!>()
|
||||
}
|
||||
|
||||
fun test2() {
|
||||
val a: A? = null;
|
||||
assert((a as B).bool())
|
||||
a?.<!UNRESOLVED_REFERENCE!>bool<!>()
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// !IGNORE_DATA_FLOW_IN_ASSERT
|
||||
// SKIP_TXT
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun test1(s: String?) {
|
||||
assert(s!!.isEmpty())
|
||||
s?.length
|
||||
}
|
||||
|
||||
fun test2(s: String?) {
|
||||
assert(s!!.isEmpty())
|
||||
s!!.length
|
||||
}
|
||||
|
||||
fun test3(s: String?) {
|
||||
assert(s!!.isEmpty())
|
||||
s<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
fun test4() {
|
||||
val s: String? = null;
|
||||
assert(s!!.isEmpty())
|
||||
s?.length
|
||||
}
|
||||
|
||||
fun test5() {
|
||||
val s: String? = null;
|
||||
assert(s!!.isEmpty())
|
||||
s!!.length
|
||||
}
|
||||
|
||||
fun test6() {
|
||||
val s: String? = null;
|
||||
assert(s!!.isEmpty())
|
||||
s<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+6
-15
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.checkers
|
||||
@@ -28,6 +17,7 @@ const val API_VERSION_DIRECTIVE = "API_VERSION"
|
||||
|
||||
const val EXPERIMENTAL_DIRECTIVE = "EXPERIMENTAL"
|
||||
const val USE_EXPERIMENTAL_DIRECTIVE = "USE_EXPERIMENTAL"
|
||||
const val IGNORE_DATA_FLOW_IN_ASSERT_DIRECTIVE = "IGNORE_DATA_FLOW_IN_ASSERT"
|
||||
const val ENABLE_JVM_DEFAULT = "ENABLE_JVM_DEFAULT"
|
||||
|
||||
data class CompilerTestLanguageVersionSettings(
|
||||
@@ -60,9 +50,10 @@ fun parseLanguageVersionSettings(directiveMap: Map<String, String>): LanguageVer
|
||||
val languageFeaturesString = directiveMap[LANGUAGE_DIRECTIVE]
|
||||
val experimental = directiveMap[EXPERIMENTAL_DIRECTIVE]?.split(' ')?.let { AnalysisFlag.experimental to it }
|
||||
val useExperimental = directiveMap[USE_EXPERIMENTAL_DIRECTIVE]?.split(' ')?.let { AnalysisFlag.useExperimental to it }
|
||||
val ignoreDataFlowInAssert = AnalysisFlag.ignoreDataFlowInAssert to directiveMap.containsKey(IGNORE_DATA_FLOW_IN_ASSERT_DIRECTIVE)
|
||||
val enableJvmDefault = AnalysisFlag.enableJvmDefault to directiveMap.containsKey(ENABLE_JVM_DEFAULT)
|
||||
|
||||
if (apiVersionString == null && languageFeaturesString == null && experimental == null && useExperimental == null) return null
|
||||
if (apiVersionString == null && languageFeaturesString == null && experimental == null && useExperimental == null && !ignoreDataFlowInAssert.second) return null
|
||||
|
||||
val apiVersion = (if (apiVersionString != null) ApiVersion.parse(apiVersionString) else ApiVersion.LATEST_STABLE)
|
||||
?: error("Unknown API version: $apiVersionString")
|
||||
@@ -73,7 +64,7 @@ fun parseLanguageVersionSettings(directiveMap: Map<String, String>): LanguageVer
|
||||
|
||||
return CompilerTestLanguageVersionSettings(
|
||||
languageFeatures, apiVersion, languageVersion,
|
||||
mapOf(*listOfNotNull(experimental, useExperimental, enableJvmDefault).toTypedArray())
|
||||
mapOf(*listOfNotNull(experimental, useExperimental, enableJvmDefault, ignoreDataFlowInAssert).toTypedArray())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+23
@@ -776,6 +776,29 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/assert")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Assert extends AbstractDiagnosticsTestWithStdLib {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInAssert() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/assert"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("cast.kt")
|
||||
public void testCast() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/assert/cast.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCall.kt")
|
||||
public void testSafeCall() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/assert/safeCall.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/builtins")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
Generated
+23
@@ -776,6 +776,29 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/assert")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Assert extends AbstractDiagnosticsTestWithStdLibUsingJavac {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInAssert() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/assert"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("cast.kt")
|
||||
public void testCast() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/assert/cast.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCall.kt")
|
||||
public void testSafeCall() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/assert/safeCall.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/builtins")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.config
|
||||
@@ -72,5 +61,8 @@ class AnalysisFlag<out T> internal constructor(
|
||||
|
||||
@JvmStatic
|
||||
val enableJvmDefault by Flag.Boolean
|
||||
|
||||
@JvmStatic
|
||||
val ignoreDataFlowInAssert by Flag.Boolean
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user