JS: underline js() errors for non-string-literal constants

This commit is contained in:
Alexey Tsvetkov
2015-02-19 12:36:34 +03:00
parent 1087ae4779
commit 180272e4cb
3 changed files with 132 additions and 4 deletions
@@ -22,6 +22,8 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages;
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticFactoryToRendererMap;
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticRenderer;
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs;
import org.jetbrains.kotlin.js.resolve.diagnostics.JsCallDataHtmlRenderer;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import static org.jetbrains.kotlin.diagnostics.Errors.*;
@@ -125,7 +127,8 @@ public class IdeErrorMessages {
MAP.put(CONFLICTING_JVM_DECLARATIONS, "<html>Platform declaration clash: {0}</html>", HTML_CONFLICTING_JVM_DECLARATIONS_DATA);
MAP.put(ACCIDENTAL_OVERRIDE, "<html>Accidental override: {0}</html>", HTML_CONFLICTING_JVM_DECLARATIONS_DATA);
MAP.put(ErrorsJs.JSCODE_ERROR, "<html>JavaScript: {0}</html>", JsCallDataHtmlRenderer.INSTANCE$);
MAP.put(ErrorsJs.JSCODE_WARNING, "<html>JavaScript: {0}</html>", JsCallDataHtmlRenderer.INSTANCE$);
MAP.setImmutable();
}
@@ -31,9 +31,9 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by Delegates.lazy {
put(ErrorsJs.NATIVE_GETTER_RETURN_TYPE_SHOULD_BE_NULLABLE, "Native getter''s return type should be nullable")
put(ErrorsJs.NATIVE_SETTER_WRONG_RETURN_TYPE, "Native setter''s return type should be ''Unit'' or a supertype of the second parameter''s type")
put(ErrorsJs.NATIVE_INDEXER_WRONG_PARAMETER_COUNT, "Expected {0} parameters for native {1}", Renderers.TO_STRING, Renderers.STRING)
put(ErrorsJs.JSCODE_ERROR, "JavaScript: {0}", Renderers.TO_STRING, Renderers.TO_STRING)
put(ErrorsJs.JSCODE_WARNING, "JavaScript: {0}", Renderers.TO_STRING, Renderers.TO_STRING)
put(ErrorsJs.JSCODE_ARGUMENT_SHOULD_BE_LITERAL, "Argument must be string literal")
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")
this
}
@@ -0,0 +1,125 @@
/*
* Copyright 2010-2015 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.
*/
package org.jetbrains.kotlin.js.resolve.diagnostics
import org.jetbrains.kotlin.renderer.Renderer
import org.jetbrains.kotlin.resolve.diagnostics.JsCallData
import org.jetbrains.kotlin.resolve.diagnostics.JsCallDataWithCode
import com.google.gwt.dev.js.rhino.Utils.isEndOfLine
abstract class JsCallDataRenderer : Renderer<JsCallData> {
protected abstract fun format(data: JsCallDataWithCode): String
override fun render(data: JsCallData?): String =
when (data) {
is JsCallDataWithCode -> format(data)
is JsCallData -> data.message
else -> throw AssertionError("Cannot render null data")
}
}
object JsCallDataTextRenderer : JsCallDataRenderer() {
override fun format(data: JsCallDataWithCode): String {
val codeRange = data.codeRange
val code = data.code.underlineAsText(codeRange.getStartOffset(), codeRange.getEndOffset())
return "${data.message} in code:\n${code}"
}
}
public object JsCallDataHtmlRenderer : JsCallDataRenderer() {
override fun format(data: JsCallDataWithCode): String {
val codeRange = data.codeRange
val code = data.code.underlineAsHtml(codeRange.getStartOffset(), codeRange.getEndOffset())
return "${data.message} in code:<br><pre>${code}</pre>"
}
}
/**
* Underlines string in given rage.
*
* For example:
* var = 10;
* ^^^^
*/
public fun String.underlineAsText(from: Int, to: Int): String {
val lines = StringBuilder()
var marks = StringBuilder()
var lineWasMarked = false
for (i in indices) {
val c = charAt(i)
val mark: Char
mark = when (i) {
in from..to -> '^'
else -> ' '
}
lines.append(c)
marks.append(mark)
lineWasMarked = lineWasMarked || mark != ' '
if (isEndOfLine(c.toInt())) {
if (lineWasMarked) {
lines.appendln(marks.toString().trimTrailing())
lineWasMarked = false
}
marks = StringBuilder()
}
}
if (lineWasMarked) {
lines.appendln()
lines.append(marks.toString())
}
return lines.toString()
}
public fun String.underlineAsHtml(from: Int, to: Int): String {
val lines = StringBuilder()
var openMarker = false
val underlineStart = "<u>"
val underlineEnd = "</u>"
for (i in indices) {
val c = charAt(i)
val mark = when (i) {
from -> {
openMarker = true
underlineStart
}
to -> {
openMarker = false
underlineEnd
}
else -> ""
}
lines.append(mark)
if (isEndOfLine(c.toInt()) && openMarker) {
lines.append(underlineEnd + c + underlineStart)
} else {
lines.append(c)
}
}
return lines.toString()
}