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

org.sonar.plugins.findbugs.resource.ByteCodeResourceLocator Maven / Gradle / Ivy

Go to download

SpotBugs is a program that uses static analysis to look for bugs in Java code. It can detect a variety of common coding mistakes, including thread synchronization problems, misuse of API methods.

There is a newer version: 4.3.0
Show newest version
/*
 * SonarQube Findbugs Plugin
 * Copyright (C) 2012 SonarSource
 * [email protected]
 *
 * 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  02
 */
package org.sonar.plugins.findbugs.resource;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import javax.annotation.Nullable;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.plugins.java.api.JavaResourceLocator;

/**
 * Utility method related to mapped class name to various resources and extracting addition information.
 */
@ScannerSide
public class ByteCodeResourceLocator {


    private static final Logger LOG = LoggerFactory.getLogger(ByteCodeResourceLocator.class);

    private static final String[] SOURCE_DIRECTORIES = {"src/main/java","src/main/webapp","src/main/resources", "src", "src/java", "app", "src/main/scala"};

    /**
     * findSourceFileKeyByClassName() is broken in SonarQube 6.3.1.. This method is fixing it.
     * @param className The name of class to find the source file
     * @param javaResourceLocator The {@link JavaResourceLocator} to find resource by classname
     * @return String filepath
     */
    public String findSourceFileKeyByClassName(String className, JavaResourceLocator javaResourceLocator) {
        InputFile input = javaResourceLocator.findResourceByClassName(className);
        if (input != null) {
            URI classFile = input.uri();
            if (classFile != null && "file".equals(classFile.getScheme())) {
                return new File(classFile).getAbsolutePath();
            }
        }

        String fileName = className.replaceAll("\\.","/")+".class";

        Collection classPathEntries = javaResourceLocator.classpath();
        for(File classPathEntry : classPathEntries) {
            if(classPathEntry.isDirectory()) { //Skip jars in the classpath

                File potentialLocation = new File(classPathEntry, fileName);
                if(potentialLocation.exists()) {
                    return potentialLocation.getPath();
                }
            }
        }
        return null;
    }

    /**
     * Find a Java source file based on the _exact_ filename passed.
     * @param sourceFile Path to the source file (/package/MyClass.java)
     * @param fs File system
     * @return The InputFile instance to the source file
     */
    public InputFile findSourceFile(String sourceFile, FileSystem fs) {
        return buildInputFile(sourceFile, fs);
    }

    /**
     * JSP files are compile to class with pseudo packages and class name that vary based on the compiler used.
     * Multiples patterns are test against the available sources files.
* (ie : test.index_jsp -> src/main/webapp/test/index.jsp) *
* Their is a certain level of guessing since their could always be a class following the same pattern of colliding * precompiled jsp. (same pseudo package, same class format, etc.) * * @param className Class name of the precompiled jsp * @param fs File system * @return The InputFile instance to the template file */ public InputFile findTemplateFile(String className, FileSystem fs) { List potentialJspFilenames = new ArrayList<>(); //Weblogic APPC precompiled form //Expected class name: "jsp_servlet._folder1._folder2.__helloworld" if(className.startsWith("jsp_servlet")) { String jspFile = className.substring(11).replaceFirst("\\.__([^\\.]+)$", "/$1\\.jsp").replace("._", "/"); potentialJspFilenames.add(jspFile); } //Jetty and Tomcat JSP precompiled form //Expected class name: "jsp.folder1.folder2.hello_005fworld_jsp" if (className.endsWith("_jsp")) { String jspFileFromClass = JasperUtils.decodeJspClassName(className); potentialJspFilenames.add(jspFileFromClass); for(String packageName : Arrays.asList("jsp/", "org/apache/jsp/")) { if(jspFileFromClass.startsWith(packageName)) potentialJspFilenames.add(jspFileFromClass.substring(packageName.length())); } } //Source directories will include typically : /src/main/java and /src/main/webapp for (String jspFilename : potentialJspFilenames) { InputFile file = buildInputFile(jspFilename, fs); if(file != null) return file; } return null; } /** * Look in the potential source directories to find the given source file * @param fileName Path to the source file (/package/MyClass.java) * @param fs File system * @return The InputFile instance to the source file */ private InputFile buildInputFile(String fileName,FileSystem fs) { for(String sourceDir : SOURCE_DIRECTORIES) { //Quick lookup to skip manual iteration (see next loop) //System.out.println("Source file tested : "+sourceDir+"/"+fileName); Iterable files = fs.inputFiles(fs.predicates().hasRelativePath(sourceDir+"/"+fileName)); for (InputFile f : files) { return f; } } //Search for path _ending_ with the filename (https://github.com/SonarQubeCommunity/sonar-findbugs/issues/51) for (InputFile f : fs.inputFiles(fs.predicates().hasType(InputFile.Type.MAIN))) { if (f.relativePath().endsWith(fileName)) { return f; } } return null; } /** * Map Java line number to JSP line number based on SMAP * * The smap can be either embedded in the class file or alternatively place in separate file. * * @param className Class name * @param originalLine Line of code of the auto-generated Java line (.jsp -> .java -> .class) * @param classFile (Optional) * @return JSP line number */ @Nullable public SmapParser.SmapLocation extractSmapLocation(String className, int originalLine, File classFile) { //Extract the SMAP (JSR45) from the class file (SourceDebugExtension section) try (InputStream in = new FileInputStream(classFile)) { DebugExtensionExtractor debug = new DebugExtensionExtractor(); String smap = debug.getDebugExtFromClass(in); if(smap != null) return getJspLineNumberFromSmap(smap, originalLine); } catch (IOException e) { LOG.warn("An error occurs while opening classfile : {}", classFile.getPath()); } LOG.debug("No smap file found for the class: " + className); //Extract the SMAP (JSR45) from the separated smap file File smapFile = new File(classFile.getPath()+".smap"); if(smapFile.exists()) { try (InputStream smapInputStream = new FileInputStream(smapFile)) { return getJspLineNumberFromSmap(IOUtils.toString(smapInputStream), originalLine); } catch (IOException e) { LOG.debug("Unable to open smap file : {} ({})", smapFile.getAbsolutePath(), e.getMessage()); } } else { LOG.debug("No smap mapping found."); } return null; //No smap file is present. } /** * * @param smap SMAP content (See smap.txt sample in test directories) * @param originalLine Java source code line number * @return JSP line number * @throws IOException */ private SmapParser.SmapLocation getJspLineNumberFromSmap(String smap, Integer originalLine) throws IOException { SmapParser parser = new SmapParser(smap); return parser.getSmapLocation(originalLine); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy