/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.renderers; import java.io.IOException; import java.io.Writer; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.StringTokenizer; import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.lang.rule.properties.StringProperty; /** * Renderer for IntelliJ IDEA integration. */ public class IDEAJRenderer extends AbstractIncrementingRenderer { private String classAndMethodName; private String fileName; public static final String NAME = "ideaj"; public static final StringProperty FILE_NAME = new StringProperty("fileName", "File name.", "", 0); public static final StringProperty SOURCE_PATH = new StringProperty("sourcePath", "Source path.", "", 1); public static final StringProperty CLASS_AND_METHOD_NAME = new StringProperty("classAndMethodName", "Class and Method name, pass '.method' when processing a directory.", "", 2); private static final String FILE_SEPARATOR = System.getProperty("file.separator"); private static final String PATH_SEPARATOR = System.getProperty("path.separator"); public IDEAJRenderer() { super(NAME, "IntelliJ IDEA integration."); definePropertyDescriptor(FILE_NAME); definePropertyDescriptor(SOURCE_PATH); definePropertyDescriptor(CLASS_AND_METHOD_NAME); } @Override public String defaultFileExtension() { return "txt"; } /** * {@inheritDoc} */ @Override public void renderFileViolations(Iterator<RuleViolation> violations) throws IOException { classAndMethodName = getProperty(CLASS_AND_METHOD_NAME); fileName = getProperty(FILE_NAME); Writer writer = getWriter(); if (".method".equals(classAndMethodName)) { // working on a directory tree renderDirectoy(writer, violations); } else { // working on one file renderFile(writer, violations); } } private void renderDirectoy(Writer writer, Iterator<RuleViolation> violations) throws IOException { SourcePath sourcePath = new SourcePath(getProperty(SOURCE_PATH)); StringBuilder buf = new StringBuilder(); while (violations.hasNext()) { buf.setLength(0); RuleViolation rv = violations.next(); buf.append(rv.getDescription() + PMD.EOL); buf.append(" at ").append(getFullyQualifiedClassName(rv.getFilename(), sourcePath)).append(".method("); buf.append(getSimpleFileName(rv.getFilename())).append(':').append(rv.getBeginLine()).append(')') .append(PMD.EOL); writer.write(buf.toString()); } } private void renderFile(Writer writer, Iterator<RuleViolation> violations) throws IOException { StringBuilder buf = new StringBuilder(); while (violations.hasNext()) { buf.setLength(0); RuleViolation rv = violations.next(); buf.append(rv.getDescription()).append(PMD.EOL); buf.append(" at ").append(classAndMethodName).append('(').append(fileName).append(':') .append(rv.getBeginLine()).append(')').append(PMD.EOL); writer.write(buf.toString()); } } private String getFullyQualifiedClassName(String fileName, SourcePath sourcePath) { String classNameWithSlashes = sourcePath.clipPath(fileName); String className = classNameWithSlashes.replace(FILE_SEPARATOR.charAt(0), '.'); return className.substring(0, className.length() - 5); } private String getSimpleFileName(String fileName) { return fileName.substring(fileName.lastIndexOf(FILE_SEPARATOR) + 1); } private static class SourcePath { private Set<String> paths = new HashSet<>(); SourcePath(String sourcePathString) { for (StringTokenizer st = new StringTokenizer(sourcePathString, PATH_SEPARATOR); st.hasMoreTokens();) { paths.add(st.nextToken()); } } public String clipPath(String fullFilename) { for (String path : paths) { if (fullFilename.startsWith(path)) { return fullFilename.substring(path.length() + 1); } } throw new RuntimeException("Couldn't find src path for " + fullFilename); } } }