All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.java.model.SmapFile Maven / Gradle / Ivy

/*
 * SonarQube Java
 * Copyright (C) 2012-2023 SonarSource SA
 * mailto:info AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.java.model;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.FilePredicates;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;

import static java.lang.Integer.parseInt;

/**
 * SMAP format is described by JSR 45
 * JSR 45 defines more generic format supporting translation from multiple languages, here we implement only subset used
 * by Jasper for JSP to Java translation.
 * 

* We expect only single JSP stratum, with single FileSection and LineSection. Moreover only single file is expected in FileSection */ public class SmapFile { private static final Pattern LINE_INFO = Pattern.compile("(?\\d+)" + "(?:#(?\\d+))?" + "(?:,(?\\d+))?:" + "(?\\d+)" + "(?:,(?\\d+))?"); private static final Logger LOG = LoggerFactory.getLogger(SmapFile.class); private final Path generatedFile; private final Map fileSection; private final List lineSection; private final Scanner sc; public SmapFile(Path rootDir, String smapString, Path uriRoot, FileSystem fileSystem) { this.sc = new Scanner(smapString); String header = sc.nextLine(); if (!"SMAP".equals(header)) { throw new IllegalStateException("Not a source map"); } String generatedFileName = sc.nextLine(); generatedFile = rootDir.resolve(generatedFileName); String defaultStratum = sc.nextLine(); if (!"JSP".equals(defaultStratum)) { throw new IllegalStateException("Not a JSP source map"); } findSection("*S JSP"); findSection("*F"); fileSection = readFileSection(uriRoot, fileSystem); findSection("*L"); lineSection = readLineSection(); } public Path getGeneratedFile() { return generatedFile; } Map getFileSection() { return fileSection; } List getLineSection() { return lineSection; } private List readLineSection() { List result = new ArrayList<>(); int lineFileId = 0; while (sc.hasNext() && !sc.hasNext("\\*.")) { String line = sc.nextLine(); Matcher matcher = LINE_INFO.matcher(line); if (matcher.matches()) { int inputStartLine = parseInt(matcher.group("inputStartLine")); String lineFileIdGroup = matcher.group("lineFileId"); if (lineFileIdGroup != null) { lineFileId = parseInt(lineFileIdGroup); } String repeatCountGroup = matcher.group("repeatCount"); int repeatCount = repeatCountGroup != null ? parseInt(repeatCountGroup) : 1; int outputStartLine = parseInt(matcher.group("outputStartLine")); String outputIncrementGroup = matcher.group("outputIncrement"); int outputIncrement = outputIncrementGroup != null ? parseInt(outputIncrementGroup) : 1; result.add(new LineInfo(inputStartLine, lineFileId, repeatCount, outputStartLine, outputIncrement)); } else { LOG.warn("Invalid line info {}", line); } } return result; } private void findSection(String section) { while (sc.hasNextLine()) { if (section.equals(sc.nextLine())) { return; } } throw new IllegalStateException("Section " + section + " not found"); } private Map readFileSection(Path uriRoot, FileSystem fileSystem) { Map result = new HashMap<>(); while (sc.hasNext() && !sc.hasNext("\\*.")) { if (sc.hasNext("\\+")) { sc.next(); int fileId = sc.nextInt(); String file = sc.next(); sc.nextLine(); String path = sc.nextLine(); InputFile inputFile = findFileWithPath(uriRoot.resolve(path), fileSystem); result.put(fileId, new FileInfo(fileId, file, path, inputFile)); } else { int fileId = sc.nextInt(); String file = sc.next(); InputFile inputFile = findFileWithPath(uriRoot.resolve(file), fileSystem); result.put(fileId, new FileInfo(fileId, file, null, inputFile)); } } return result; } @CheckForNull private static InputFile findFileWithPath(Path path, FileSystem fileSystem) { FilePredicates predicates = fileSystem.predicates(); return fileSystem.inputFile(predicates.hasPath(path.toString())); } @Override public String toString() { return generatedFile.toString(); } Optional getInputFile(int fileId) { return Optional.ofNullable(fileSection.get(fileId)) .map(info -> info.inputFile); } static class FileInfo { final int fileId; final String sourceName; final String sourcePath; final InputFile inputFile; FileInfo(int fileId, String sourceName, @Nullable String sourcePath, @Nullable InputFile inputFile) { this.fileId = fileId; this.sourceName = sourceName; this.sourcePath = sourcePath; this.inputFile = inputFile; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } FileInfo fileInfo = (FileInfo) o; return fileId == fileInfo.fileId && Objects.equals(sourceName, fileInfo.sourceName) && Objects.equals(sourcePath, fileInfo.sourcePath); } @Override public int hashCode() { return Objects.hash(fileId, sourceName, sourcePath); } @Override public String toString() { return "FileInfo{" + "fileId=" + fileId + ", sourceName='" + sourceName + '\'' + ", sourcePath='" + sourcePath + '\'' + '}'; } } static class LineInfo { final int inputStartLine; final int lineFileId; final int repeatCount; final int outputStartLine; final int outputLineIncrement; LineInfo(int inputStartLine, int lineFileId, int repeatCount, int outputStartLine, int outputLineIncrement) { this.inputStartLine = inputStartLine; this.lineFileId = lineFileId; this.repeatCount = repeatCount; this.outputStartLine = outputStartLine; this.outputLineIncrement = outputLineIncrement; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } LineInfo lineInfo = (LineInfo) o; return inputStartLine == lineInfo.inputStartLine && lineFileId == lineInfo.lineFileId && repeatCount == lineInfo.repeatCount && outputStartLine == lineInfo.outputStartLine && outputLineIncrement == lineInfo.outputLineIncrement; } @Override public int hashCode() { return Objects.hash(inputStartLine, lineFileId, repeatCount, outputStartLine, outputLineIncrement); } @Override public String toString() { return "LineInfo{" + "inputStartLine=" + inputStartLine + ", lineFileId=" + lineFileId + ", repeatCount=" + repeatCount + ", outputStartLine=" + outputStartLine + ", outputLineIncrement=" + outputLineIncrement + '}'; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy