summaryrefslogtreecommitdiff
path: root/platform/script-debugger/debugger-ui/src/com/intellij/javascript/debugger/NameMapper.kt
diff options
context:
space:
mode:
Diffstat (limited to 'platform/script-debugger/debugger-ui/src/com/intellij/javascript/debugger/NameMapper.kt')
-rw-r--r--platform/script-debugger/debugger-ui/src/com/intellij/javascript/debugger/NameMapper.kt114
1 files changed, 114 insertions, 0 deletions
diff --git a/platform/script-debugger/debugger-ui/src/com/intellij/javascript/debugger/NameMapper.kt b/platform/script-debugger/debugger-ui/src/com/intellij/javascript/debugger/NameMapper.kt
new file mode 100644
index 00000000..c75eae1f
--- /dev/null
+++ b/platform/script-debugger/debugger-ui/src/com/intellij/javascript/debugger/NameMapper.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2000-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.
+ */
+package com.intellij.javascript.debugger
+
+import com.google.common.base.CharMatcher
+import com.intellij.openapi.editor.Document
+import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiNamedElement
+import gnu.trove.THashMap
+import org.jetbrains.debugger.sourcemap.MappingEntry
+import org.jetbrains.debugger.sourcemap.Mappings
+import org.jetbrains.debugger.sourcemap.SourceMap
+import org.jetbrains.rpc.LOG
+
+private val S1 = ",()[]{}="
+// don't trim trailing .&: - could be part of expression
+private val OPERATOR_TRIMMER = CharMatcher.INVISIBLE.or(CharMatcher.anyOf(S1))
+
+val NAME_TRIMMER: CharMatcher = CharMatcher.INVISIBLE.or(CharMatcher.anyOf(S1 + ".&:"))
+
+// generateVirtualFile only for debug purposes
+open class NameMapper(private val document: Document, private val transpiledDocument: Document, private val sourceMappings: Mappings, protected val sourceMap: SourceMap, private val transpiledFile: VirtualFile? = null) {
+ var rawNameToSource: MutableMap<String, String>? = null
+ private set
+
+ // PsiNamedElement, JSVariable for example
+ // returns generated name
+ open fun map(identifierOrNamedElement: PsiElement): String? {
+ return doMap(identifierOrNamedElement, false)
+ }
+
+ protected fun doMap(identifierOrNamedElement: PsiElement, mapBySourceCode: Boolean): String? {
+ val offset = identifierOrNamedElement.textOffset
+ val line = document.getLineNumber(offset)
+
+ val sourceEntryIndex = sourceMappings.indexOf(line, offset - document.getLineStartOffset(line))
+ if (sourceEntryIndex == -1) {
+ return null
+ }
+
+ val sourceEntry = sourceMappings.getByIndex(sourceEntryIndex)
+ val next = sourceMappings.getNextOnTheSameLine(sourceEntryIndex, false)
+ if (next != null && sourceMappings.getColumn(next) == sourceMappings.getColumn(sourceEntry)) {
+ warnSeveralMapping(identifierOrNamedElement)
+ return null
+ }
+
+ val generatedName: String?
+ try {
+ generatedName = extractName(getGeneratedName(transpiledDocument, sourceMap, sourceEntry))
+ }
+ catch (e: IndexOutOfBoundsException) {
+ LOG.warn("Cannot get generated name: source entry (${sourceEntry.generatedLine}, ${sourceEntry.generatedColumn}). Transpiled File: " + transpiledFile?.path)
+ return null
+ }
+ if (generatedName == null || generatedName.isEmpty()) {
+ return null
+ }
+
+ var sourceName = sourceEntry.name
+ if (sourceName == null || mapBySourceCode) {
+ sourceName = (identifierOrNamedElement as? PsiNamedElement)?.name ?: identifierOrNamedElement.text ?: sourceName ?: return null
+ }
+
+ addMapping(generatedName, sourceName)
+ return generatedName
+ }
+
+ fun addMapping(generatedName: String, sourceName: String) {
+ if (rawNameToSource == null) {
+ rawNameToSource = THashMap<String, String>()
+ }
+ rawNameToSource!!.put(generatedName, sourceName)
+ }
+
+ protected open fun extractName(rawGeneratedName: CharSequence):String? = NAME_TRIMMER.trimFrom(rawGeneratedName)
+
+ companion object {
+ fun trimName(rawGeneratedName: CharSequence, isLastToken: Boolean): String? = (if (isLastToken) NAME_TRIMMER else OPERATOR_TRIMMER).trimFrom(rawGeneratedName)
+ }
+}
+
+fun warnSeveralMapping(element: PsiElement) {
+ // see https://dl.dropboxusercontent.com/u/43511007/s/Screen%20Shot%202015-01-21%20at%2020.33.44.png
+ // var1 mapped to the whole "var c, notes, templates, ..." expression text + unrelated text " ;"
+ LOG.warn("incorrect sourcemap, several mappings for named element ${element.text}")
+}
+
+private fun getGeneratedName(document: Document, sourceMap: SourceMap, sourceEntry: MappingEntry): CharSequence {
+ val lineStartOffset = document.getLineStartOffset(sourceEntry.generatedLine)
+ val nextGeneratedMapping = sourceMap.generatedMappings.getNextOnTheSameLine(sourceEntry)
+ val endOffset: Int
+ if (nextGeneratedMapping == null) {
+ endOffset = document.getLineEndOffset(sourceEntry.generatedLine)
+ }
+ else {
+ endOffset = lineStartOffset + nextGeneratedMapping.generatedColumn
+ }
+ return document.immutableCharSequence.subSequence(lineStartOffset + sourceEntry.generatedColumn, endOffset)
+} \ No newline at end of file