/* * Copyright 2000-2014 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.rt.coverage.instrumentation; import com.intellij.rt.coverage.data.FileMapData; import com.intellij.rt.coverage.data.LineMapData; import gnu.trove.THashSet; import gnu.trove.TIntObjectHashMap; import java.util.*; /** * @author anna * @since 2/8/11 */ public class JSR45Util { private static final String FILE_SECTION = "*F\n"; private static final String LINE_SECTION = "*L\n"; private static final String END_SECTION = "*E"; public static FileMapData[] extractLineMapping(String debug, String className) { if (debug.startsWith("SMAP")) { final TIntObjectHashMap linesMap = new TIntObjectHashMap(); debug = debug.substring(4); final int fileSectionIdx = debug.indexOf(FILE_SECTION); final int lineInfoIdx = debug.indexOf(LINE_SECTION); final String[] fileNames = parseFileNames(debug.substring(fileSectionIdx + FILE_SECTION.length(), lineInfoIdx), className); final String lineInfo = debug.substring(lineInfoIdx + LINE_SECTION.length(), debug.indexOf(END_SECTION)); final String[] lines = lineInfo.split("\n"); int fileId = 1; for (int i = 0; i < lines.length; i++) { //InputStartLine # LineFileID , RepeatCount : OutputStartLine , OutputLineIncrement int startSrcLine; int repeat = 1; int startOutLine; int outLineInc = 1; final int idx = lines[i].indexOf(":"); final String srcLine = lines[i].substring(0, idx); final String outLine = lines[i].substring(idx + 1); final int srcCommaIdx = srcLine.indexOf(','); final int sharpIdx = srcLine.indexOf("#"); if (sharpIdx > -1) { startSrcLine = Integer.parseInt(srcLine.substring(0, sharpIdx)); if (srcCommaIdx > -1) { repeat = Integer.parseInt(srcLine.substring(srcCommaIdx + 1)); fileId = Integer.parseInt(srcLine.substring(sharpIdx + 1, srcCommaIdx)); } else { fileId = Integer.parseInt(srcLine.substring(sharpIdx + 1)); } } else if (srcCommaIdx > -1) { repeat = Integer.parseInt(srcLine.substring(srcCommaIdx + 1)); startSrcLine = Integer.parseInt(srcLine.substring(0, srcCommaIdx)); } else { startSrcLine = Integer.parseInt(srcLine); } final int outCommaIdx = outLine.indexOf(','); if (outCommaIdx > -1) { outLineInc = Integer.parseInt(outLine.substring(outCommaIdx + 1)); startOutLine = Integer.parseInt(outLine.substring(0, outCommaIdx)); } else { startOutLine = Integer.parseInt(outLine); } THashSet currentFile = (THashSet) linesMap.get(fileId); if (currentFile == null) { currentFile = new THashSet(); linesMap.put(fileId, currentFile); } for (int r = 0; r < repeat; r++) { currentFile.add(new LineMapData(startSrcLine + r, startOutLine + r * outLineInc, startOutLine + (r + 1) * outLineInc - 1)); } } final List result = new ArrayList(); final int[] keys = linesMap.keys(); Arrays.sort(keys); for (int i = 0; i < keys.length; i++) { final int key = keys[i]; result.add(new FileMapData(fileNames[key - 1], getLinesMapping((THashSet) linesMap.get(key)))); } return (FileMapData[]) result.toArray(new FileMapData[result.size()]); } return null; } public static String[] parseFileNames(String fileSection, String className) { fileSection = fileSection.trim(); if (fileSection.endsWith("\n")) { fileSection = fileSection.substring(0, fileSection.length() - 1); } final String[] fileNameIdx = fileSection.split("\n"); final String[] result = new String[fileNameIdx.length / 2]; for (int i = 0; i < fileNameIdx.length; i++) { String fileName = fileNameIdx[i]; if (fileName.startsWith("+")) continue; if (i / 2 == 0) { result[0] = className; } else { fileName = processRelative(fileName); final int lastDot = fileName.lastIndexOf("."); final String fileNameWithDots; if (lastDot < 0) { fileNameWithDots = fileName; } else { fileNameWithDots = fileName.substring(0, lastDot) + "_" + fileName.substring(lastDot + 1); } result[i / 2] = getClassPackageName(className) + fileNameWithDots.replace('/', '.'); } } return result; } public static String processRelative(String fileName) { int idx; while ((idx = fileName.indexOf("..")) > -1) { final String rest = fileName.substring(idx + "..".length()); String start = fileName.substring(0, idx); if (!start.endsWith("/")) return fileName; start = start.substring(0, start.length() - 1); final int endIndex = start.lastIndexOf('/'); if (endIndex > -1) { fileName = start.substring(0, endIndex) + rest; } else { fileName = rest.startsWith("/") ? rest.substring(1) : rest; } } return fileName; } private static String getClassPackageName(String className) { String generatePrefix = ""; final int fqnLastDotIdx = className.lastIndexOf("."); if (fqnLastDotIdx > -1) { generatePrefix = className.substring(0, fqnLastDotIdx + 1); } return generatePrefix; } static LineMapData[] getLinesMapping(THashSet linesMap) { int max = 0; for (Iterator iterator = linesMap.iterator(); iterator.hasNext(); ) { LineMapData lmd = (LineMapData) iterator.next(); if (max < lmd.getSourceLineNumber()) { max = lmd.getSourceLineNumber(); } } final LineMapData[] result = new LineMapData[max + 1]; for (Iterator iterator = linesMap.iterator(); iterator.hasNext(); ) { LineMapData lmd = (LineMapData) iterator.next(); result[lmd.getSourceLineNumber()] = lmd; } return result; } }