diff --git a/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java b/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java index 2925ce0dc6..b3a54e706b 100644 --- a/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java +++ b/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.docs; +import java.io.File; import java.io.IOException; import java.nio.file.FileVisitResult; import java.nio.file.Files; @@ -42,6 +43,8 @@ public class RuleDocGenerator { private static final String DEPRECATION_LABEL_SMALL = "Deprecated "; private static final String DEPRECATION_LABEL = "Deprecated "; + private static final String GITHUB_SOURCE_LINK = "https://github.com/pmd/pmd/blob/master/"; + private final Path root; private final FileWriter writer; @@ -277,7 +280,7 @@ public class RuleDocGenerator { lines.add(""); } if (rule.getSince() != null) { - lines.add("**Since:** " + rule.getSince()); + lines.add("**Since:** PMD " + rule.getSince()); lines.add(""); } lines.add("**Priority:** " + rule.getPriority() + " (" + rule.getPriority().getPriority() + ")"); @@ -285,6 +288,20 @@ public class RuleDocGenerator { lines.add(StringUtils.stripToEmpty(rule.getDescription())); lines.add(""); + + if (rule instanceof XPathRule || rule instanceof RuleReference && ((RuleReference) rule).getRule() instanceof XPathRule) { + lines.add("```"); + lines.add(StringUtils.stripToEmpty(rule.getProperty(XPathRule.XPATH_DESCRIPTOR))); + lines.add("```"); + lines.add(""); + } else { + lines.add("**This rule is defined by the following Java class:** " + + "[" + rule.getRuleClass() + "](" + + GITHUB_SOURCE_LINK + getRuleClassSourceFilepath(rule.getRuleClass()) + + ")"); + lines.add(""); + } + if (!rule.getExamples().isEmpty()) { lines.add("**Example(s):**"); lines.add(""); @@ -358,7 +375,7 @@ public class RuleDocGenerator { return super.visitFile(file, attrs); } }); - + if (!foundPathResult.isEmpty()) { Path foundPath = foundPathResult.get(0); foundPath = root.relativize(foundPath); @@ -367,4 +384,29 @@ public class RuleDocGenerator { return StringUtils.chomp(ruleset.getFileName()); } + + private String getRuleClassSourceFilepath(String ruleClass) throws IOException { + final String relativeSourceFilename = ruleClass.replaceAll("\\.", File.separator) + ".java"; + final List foundPathResult = new LinkedList<>(); + + Files.walkFileTree(root, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + String path = file.toString(); + if (path.contains("src") && path.endsWith(relativeSourceFilename)) { + foundPathResult.add(file); + return FileVisitResult.TERMINATE; + } + return super.visitFile(file, attrs); + } + }); + + if (!foundPathResult.isEmpty()) { + Path foundPath = foundPathResult.get(0); + foundPath = root.relativize(foundPath); + return FilenameUtils.normalize(foundPath.toString(), true); + } + + return FilenameUtils.normalize(relativeSourceFilename, true); + } } diff --git a/pmd-doc/src/test/resources/expected/sample.md b/pmd-doc/src/test/resources/expected/sample.md index bc50e5667d..2ff1e05272 100644 --- a/pmd-doc/src/test/resources/expected/sample.md +++ b/pmd-doc/src/test/resources/expected/sample.md @@ -10,20 +10,33 @@ editmepath: ../rulesets/ruledoctest/sample.xml Deprecated -**Since:** 1.0 +**Since:** PMD 1.0 **Priority:** Medium (3) Just some description of a deprecated rule. +``` +//ForStatement +``` + ## JumbledIncrementer -**Since:** 1.0 +**Since:** PMD 1.0 **Priority:** Medium (3) Avoid jumbled loop incrementers - its usually a mistake, and is confusing even if intentional. +``` +//ForStatement + [ + ForUpdate/StatementExpressionList/StatementExpression/PostfixExpression/PrimaryExpression/PrimaryPrefix/Name/@Image + = + ancestor::ForStatement/ForInit//VariableDeclaratorId/@Image + ] +``` + **Example(s):** ``` @@ -44,12 +57,21 @@ public class JumbledIncrementerRule1 { The rule has been moved to another ruleset. Use instead: [JumbledIncrementer](pmd_rules_java_basic.html#jumbledincrementer) -**Since:** 1.0 +**Since:** PMD 1.0 **Priority:** Medium (3) Avoid jumbled loop incrementers - its usually a mistake, and is confusing even if intentional. +``` +//ForStatement + [ + ForUpdate/StatementExpressionList/StatementExpression/PostfixExpression/PrimaryExpression/PrimaryPrefix/Name/@Image + = + ancestor::ForStatement/ForInit//VariableDeclaratorId/@Image + ] +``` + **Example(s):** ``` @@ -66,12 +88,14 @@ public class JumbledIncrementerRule1 { ## OverrideBothEqualsAndHashcode -**Since:** 0.4 +**Since:** PMD 0.4 **Priority:** Medium (3) Override both public boolean Object.equals(Object other), and public int Object.hashCode(), or override neither. Even if you are inheriting a hashCode() from a parent class, consider implementing hashCode and explicitly delegating to your superclass. +**This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.java.rule.basic.OverrideBothEqualsAndHashcodeRule](https://github.com/pmd/pmd/blob/master/net/sourceforge/pmd/lang/java/rule/basic/OverrideBothEqualsAndHashcodeRule.java) + **Example(s):** ``` @@ -103,12 +127,21 @@ public class Foo { // perfect, both methods provided This rule has been renamed. Use instead: [JumbledIncrementer](#jumbledincrementer) -**Since:** 1.0 +**Since:** PMD 1.0 **Priority:** Medium (3) Avoid jumbled loop incrementers - its usually a mistake, and is confusing even if intentional. +``` +//ForStatement + [ + ForUpdate/StatementExpressionList/StatementExpression/PostfixExpression/PrimaryExpression/PrimaryPrefix/Name/@Image + = + ancestor::ForStatement/ForInit//VariableDeclaratorId/@Image + ] +``` + **Example(s):** ```