[JS PSI] Deprecate using not constant variables in js() calls

Added JSCODE_ARGUMENT_NON_CONST_EXPRESSION warning which
checks non constant variable usages in js() argument expressions.

The fix is related to KT-57156.
This commit is contained in:
Alexander Korepanov
2023-10-17 14:26:50 +02:00
committed by Space Team
parent 2b2b8dd090
commit 720fe2ac89
3 changed files with 19 additions and 4 deletions
@@ -24,6 +24,7 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
put(ErrorsJs.JSCODE_ERROR, "JavaScript: {0}", JsCallDataTextRenderer)
put(ErrorsJs.JSCODE_WARNING, "JavaScript: {0}", JsCallDataTextRenderer)
put(ErrorsJs.JSCODE_ARGUMENT_SHOULD_BE_CONSTANT, "Argument must be string constant")
put(ErrorsJs.JSCODE_ARGUMENT_NON_CONST_EXPRESSION, "Using not constant variables in js() argument expression becomes deprecated and will be an error in future releases")
put(ErrorsJs.NOT_SUPPORTED, "Cannot translate (not supported yet): ''{0}''", RenderFirstLineOfElementText)
put(ErrorsJs.JSCODE_NO_JAVASCRIPT_PRODUCED, "Argument must be non-empty JavaScript code")
put(ErrorsJs.NESTED_EXTERNAL_DECLARATION, "Non top-level `external` declaration")
@@ -27,6 +27,7 @@ public interface ErrorsJs {
DiagnosticFactory1<KtExpression, JsCallData> JSCODE_ERROR = DiagnosticFactory1.create(ERROR, JsCodePositioningStrategy.INSTANCE);
DiagnosticFactory1<KtExpression, JsCallData> JSCODE_WARNING = DiagnosticFactory1.create(WARNING, JsCodePositioningStrategy.INSTANCE);
DiagnosticFactory0<KtExpression> JSCODE_ARGUMENT_SHOULD_BE_CONSTANT = DiagnosticFactory0.create(ERROR, DEFAULT);
DiagnosticFactory0<KtExpression> JSCODE_ARGUMENT_NON_CONST_EXPRESSION = DiagnosticFactory0.create(WARNING, DEFAULT);
DiagnosticFactory1<KtElement, KtElement> NOT_SUPPORTED = DiagnosticFactory1.create(ERROR, DEFAULT);
DiagnosticFactory0<KtExpression> JSCODE_NO_JAVASCRIPT_PRODUCED = DiagnosticFactory0.create(ERROR, DEFAULT);
DiagnosticFactory1<KtExpression, String> WRONG_EXTERNAL_DECLARATION = DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
@@ -25,6 +25,7 @@ import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1
import org.jetbrains.kotlin.js.backend.ast.JsFunctionScope
import org.jetbrains.kotlin.js.backend.ast.JsProgram
@@ -33,15 +34,13 @@ import org.jetbrains.kotlin.js.parser.parseExpressionOrStatement
import org.jetbrains.kotlin.js.patterns.DescriptorPredicate
import org.jetbrains.kotlin.js.patterns.PatternBuilder
import org.jetbrains.kotlin.js.resolve.LEXICAL_SCOPE_FOR_JS
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant
@@ -84,6 +83,20 @@ class JsCallChecker(
return
}
argument.accept(object : KtVisitor<Nothing?, Nothing?>() {
override fun visitElement(element: PsiElement) {
element.acceptChildren(this)
}
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression, data: Nothing?): Nothing? {
val variableAccessing = (expression.getResolvedCall(trace.bindingContext)?.resultingDescriptor as? VariableDescriptor)
if (variableAccessing?.isConst == false) {
context.trace.report(ErrorsJs.JSCODE_ARGUMENT_NON_CONST_EXPRESSION.on(expression))
}
return super.visitSimpleNameExpression(expression, data)
}
})
trace.commit()
val errorReporter = JsCodeErrorReporter(argument, code, context.trace)