eff825bed7
TRAVIS_JOB_NUMBER=3428.2 TRAVIS_COMMIT_RANGE=be73856c7c7974d00388f9728beeefd35370aaf8...cfe07822be49311797a539a9b3cffb4de4fb512e
1642 lines
56 KiB
HTML
1642 lines
56 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="description" content="Learn how to write a custom rule for PMD">
|
||
<meta name="keywords" content="extendinguserdocs, ">
|
||
<title>Writing a custom rule | PMD Source Code Analyzer</title>
|
||
<link rel="stylesheet" href="css/syntax.css">
|
||
|
||
|
||
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
|
||
<!--<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">-->
|
||
<link rel="stylesheet" href="css/modern-business.css">
|
||
<link rel="stylesheet" href="css/lavish-bootstrap.css">
|
||
<link rel="stylesheet" href="css/customstyles.css">
|
||
<link rel="stylesheet" href="css/theme-blue.css">
|
||
<link rel="stylesheet" href="css/pmd-customstyles.css">
|
||
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
|
||
<script src="js/jquery.navgoco.min.js"></script>
|
||
|
||
|
||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/anchor-js/2.0.0/anchor.min.js"></script>
|
||
<script src="js/toc.js"></script>
|
||
<script src="js/customscripts.js"></script>
|
||
|
||
<link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon">
|
||
<link rel="icon" href="images/favicon.ico" type="image/x-icon">
|
||
|
||
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||
<!--[if lt IE 9]>
|
||
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
|
||
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
|
||
<![endif]-->
|
||
|
||
<link rel="alternate" type="application/rss+xml" title="" href="https://pmd.github.io/pmd/feed.xml">
|
||
|
||
<script>
|
||
$(document).ready(function() {
|
||
// Initialize navgoco with default options
|
||
$("#mysidebar").navgoco({
|
||
caretHtml: '',
|
||
accordion: true,
|
||
openClass: 'active', // open
|
||
save: false, // leave false or nav highlighting doesn't work right
|
||
cookie: {
|
||
name: 'navgoco',
|
||
expires: false,
|
||
path: '/'
|
||
},
|
||
slide: {
|
||
duration: 400,
|
||
easing: 'swing'
|
||
}
|
||
});
|
||
|
||
$("#collapseAll").click(function(e) {
|
||
e.preventDefault();
|
||
$("#mysidebar").navgoco('toggle', false);
|
||
});
|
||
|
||
$("#expandAll").click(function(e) {
|
||
e.preventDefault();
|
||
$("#mysidebar").navgoco('toggle', true);
|
||
});
|
||
|
||
});
|
||
|
||
</script>
|
||
<script>
|
||
$(function () {
|
||
$('[data-toggle="tooltip"]').tooltip()
|
||
})
|
||
</script>
|
||
<script>
|
||
$(document).ready(function() {
|
||
$("#tg-sb-link").click(function() {
|
||
$("#tg-sb-sidebar").toggle();
|
||
$("#tg-sb-content").toggleClass('col-md-9');
|
||
$("#tg-sb-content").toggleClass('col-md-12');
|
||
$("#tg-sb-icon").toggleClass('fa-toggle-on');
|
||
$("#tg-sb-icon").toggleClass('fa-toggle-off');
|
||
});
|
||
});
|
||
</script>
|
||
|
||
|
||
</head>
|
||
<body>
|
||
<!-- Content is offset by the height of the topnav bar. -->
|
||
<!-- There's already a padding-top rule in modern-business.css, but it apparently doesn't work on Firefox 60 and Chrome 67 -->
|
||
<div id="topbar-content-offset">
|
||
<!-- Navigation -->
|
||
<nav class="navbar navbar-inverse navbar-fixed-top">
|
||
<div class="container topnavlinks">
|
||
<div class="navbar-header">
|
||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||
<span class="sr-only">Toggle navigation</span>
|
||
<span class="icon-bar"></span>
|
||
<span class="icon-bar"></span>
|
||
<span class="icon-bar"></span>
|
||
</button>
|
||
<a class="fa fa-home fa-lg navbar-brand" href="index.html"> <span class="projectTitle"> PMD Source Code Analyzer Project</span></a>
|
||
</div>
|
||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||
<ul class="nav navbar-nav navbar-right">
|
||
<!-- toggle sidebar button -->
|
||
<li><a id="tg-sb-link" href="#"><i id="tg-sb-icon" class="fa fa-toggle-on"></i> Nav</a></li>
|
||
<!-- entries without drop-downs appear here -->
|
||
|
||
|
||
|
||
<li><a href="https://github.com/pmd/pmd/releases/latest" target="_blank">Download</a></li>
|
||
|
||
|
||
|
||
<li><a href="https://github.com/pmd/pmd" target="_blank">Fork us on github</a></li>
|
||
|
||
|
||
|
||
<!-- entries with drop-downs appear here -->
|
||
<!-- conditional logic to control which topnav appears for the audience defined in the configuration file.-->
|
||
|
||
|
||
<!--comment out this block if you want to hide search-->
|
||
<li>
|
||
<!--start search-->
|
||
<div id="search-demo-container">
|
||
<input type="text" id="search-input" placeholder="search...">
|
||
<ul id="results-container"></ul>
|
||
</div>
|
||
<script src="js/jekyll-search.js" type="text/javascript"></script>
|
||
<script type="text/javascript">
|
||
SimpleJekyllSearch.init({
|
||
searchInput: document.getElementById('search-input'),
|
||
resultsContainer: document.getElementById('results-container'),
|
||
dataSource: 'search.json',
|
||
searchResultTemplate: '<li><a href="{url}" title="Writing a custom rule">{title}</a></li>',
|
||
noResultsText: 'No results found.',
|
||
limit: 10,
|
||
fuzzy: true,
|
||
})
|
||
</script>
|
||
<!--end search-->
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<!-- /.container -->
|
||
</nav>
|
||
|
||
<!-- Page Content -->
|
||
<div class="container">
|
||
<div class="col-lg-12"> </div>
|
||
<!-- Content Row -->
|
||
<div class="row">
|
||
|
||
|
||
<!-- Sidebar Column -->
|
||
<div class="col-md-3" id="tg-sb-sidebar">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<ul id="mysidebar" class="nav">
|
||
<li class="sidebarTitle">PMD 6.12.0</li>
|
||
|
||
|
||
|
||
|
||
|
||
<li>
|
||
|
||
<a href="#">About</a>
|
||
|
||
<ul>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="index.html">Home</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_release_notes.html">Release notes</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_next_major_development.html">PMD 7.0.0 development</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_about_help.html">Getting help</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
<li>
|
||
|
||
<a href="#">User Documentation</a>
|
||
|
||
<ul>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_installation.html">Installation and basic CLI usage</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_making_rulesets.html">Making rulesets</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_configuring_rules.html">Configuring rules</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_best_practices.html">Best practices</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_suppressing_warnings.html">Suppressing warnings</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_incremental_analysis.html">Incremental analysis</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_cli_reference.html">PMD CLI reference</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">Extending PMD</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li class="active"><a href="pmd_userdocs_extending_writing_pmd_rules.html">Writing a rule</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_extending_writing_xpath_rules.html">Writing XPath rules</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_extending_defining_properties.html">Defining rule properties</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_extending_metrics_howto.html">Using and defining code metrics</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_extending_rule_guidelines.html">Rule guidelines</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_extending_testing.html">Testing your rules</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_cpd.html">Copy-paste detection</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">Tools / Integrations</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_tools_maven.html">Maven PMD plugin</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_tools_ant.html">Ant</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_tools_ci.html">CI integrations</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_userdocs_tools.html">Other Tools / Integrations</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
<li>
|
||
|
||
<a href="#">Rule Reference</a>
|
||
|
||
<ul>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">Apex Rules</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_apex.html">Index</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_apex_bestpractices.html">Best Practices</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_apex_codestyle.html">Code Style</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_apex_design.html">Design</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_apex_documentation.html">Documentation</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_apex_errorprone.html">Error Prone</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_apex_performance.html">Performance</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_apex_security.html">Security</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">Ecmascript Rules</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_ecmascript.html">Index</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_ecmascript_bestpractices.html">Best Practices</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_ecmascript_codestyle.html">Code Style</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_ecmascript_errorprone.html">Error Prone</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">Java Rules</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_java.html">Index</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_java_bestpractices.html">Best Practices</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_java_codestyle.html">Code Style</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_java_design.html">Design</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_java_documentation.html">Documentation</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_java_errorprone.html">Error Prone</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_java_multithreading.html">Multithreading</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_java_performance.html">Performance</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_java_security.html">Security</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">Java Server Pages Rules</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_jsp.html">Index</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_jsp_bestpractices.html">Best Practices</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_jsp_codestyle.html">Code Style</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_jsp_design.html">Design</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_jsp_errorprone.html">Error Prone</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_jsp_security.html">Security</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">Maven POM Rules</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_pom.html">Index</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_pom_errorprone.html">Error Prone</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">PLSQL Rules</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_plsql.html">Index</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_plsql_bestpractices.html">Best Practices</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_plsql_codestyle.html">Code Style</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_plsql_design.html">Design</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_plsql_errorprone.html">Error Prone</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">Salesforce VisualForce Rules</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_vf.html">Index</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_vf_security.html">Security</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">VM Rules</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_vm.html">Index</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_vm_bestpractices.html">Best Practices</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_vm_design.html">Design</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_vm_errorprone.html">Error Prone</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">XML Rules</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_xml.html">Index</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_xml_errorprone.html">Error Prone</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">XSL Rules</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_xsl.html">Index</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_xsl_codestyle.html">Code Style</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_rules_xsl_performance.html">Performance</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
<li>
|
||
|
||
<a href="#">Language Specific Documentation</a>
|
||
|
||
<ul>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_languages_jsp.html">JSP Support</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_java_metrics_index.html">Java code metrics</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_apex_metrics_index.html">Apex code metrics</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
<li>
|
||
|
||
<a href="#">Developer Documentation</a>
|
||
|
||
<ul>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_devdocs_development.html">Developer resources</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_devdocs_building.html">Building PMD from source</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="https://github.com/pmd/pmd/blob/master/CONTRIBUTING.md" target="_blank">Contributing</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_devdocs_writing_documentation.html">Writing documentation</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_devdocs_roadmap.html">Roadmap</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_devdocs_how_pmd_works.html">How PMD works</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_devdocs_pmdtester.html">Pmdtester</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">Major contributions</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li><a href="pmd_devdocs_major_adding_new_language.html">Adding a new language</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_devdocs_major_adding_new_cpd_language.html">Adding a new CPD language</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_devdocs_major_adding_new_metrics_framework.html">Adding metrics support to a language</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
<li>
|
||
|
||
<a href="#">Project documentation</a>
|
||
|
||
<ul>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">Trivia about PMD</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li><a href="pmd_projectdocs_trivia_news.html">PMD in the press</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_projectdocs_trivia_products.html">Products & books related to PMD</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_projectdocs_trivia_similarprojects.html">Similar projects</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_projectdocs_trivia_meaning.html">What does 'PMD' mean?</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_projectdocs_faq.html">FAQ</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="license.html">License</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_projectdocs_credits.html">Credits</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_release_notes_old.html">Old release notes</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="subfolders">
|
||
<a href="#">Project management</a>
|
||
<ul>
|
||
|
||
|
||
|
||
<li><a href="pmd_projectdocs_committers_releasing.html">Release process</a></li>
|
||
|
||
|
||
|
||
|
||
|
||
<li><a href="pmd_projectdocs_committers_merging_pull_requests.html">Merging pull requests</a></li>
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</li>
|
||
|
||
|
||
|
||
<!-- if you aren't using the accordion, uncomment this block:
|
||
<p class="external">
|
||
<a href="#" id="collapseAll">Collapse All</a> | <a href="#" id="expandAll">Expand All</a>
|
||
</p>
|
||
-->
|
||
</ul>
|
||
|
||
<!-- this highlights the active parent class in the navgoco sidebar. this is critical so that the parent expands when you're viewing a page. This must appear below the sidebar code above. Otherwise, if placed inside customscripts.js, the script runs before the sidebar code runs and the class never gets inserted.-->
|
||
<script>$("li.active").parents('li').toggleClass("active");</script>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<!-- Content Column -->
|
||
<div class="col-md-9" id="tg-sb-content">
|
||
<div class="post-header">
|
||
<h1 class="post-title-main">Writing a custom rule</h1>
|
||
</div>
|
||
|
||
|
||
|
||
<div class="post-content">
|
||
|
||
|
||
<div class="summary">Learn how to write a custom rule for PMD</div>
|
||
|
||
|
||
|
||
|
||
<!-- this handles the automatic toc. use ## for subheads to auto-generate the on-page minitoc. if you use html tags, you must supply an ID for the heading element in order for it to appear in the minitoc. -->
|
||
<script>
|
||
$( document ).ready(function() {
|
||
// Handler for .ready() called.
|
||
|
||
$('#toc').toc({ minimumHeaders: 0, listType: 'ul', showSpeed: 0, headers: 'h2,h3,h4' });
|
||
|
||
});
|
||
</script>
|
||
|
||
<div id="toc"></div>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<a target="_blank" href="https://github.com/pmd/pmd/blob/master/docs/pages/pmd/userdocs/extending/writing_pmd_rules.md" class="btn btn-default githubEditButton" role="button"><i class="fa fa-github fa-lg"></i> Edit me</a>
|
||
|
||
|
||
|
||
<h1 id="how-to-write-a-pmd-rule">How to write a PMD rule</h1>
|
||
|
||
<p>Writing PMD rules is cool because you don’t have to wait for us to get around to implementing feature requests.</p>
|
||
|
||
<h2 id="get-a-development-environment-set-up-first">Get a development environment set up first</h2>
|
||
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Here’s some initial information on compiling PMD]
|
||
</code></pre></div></div>
|
||
|
||
<h2 id="java-or-xpath">Java or XPath?</h2>
|
||
|
||
<p>There are two way to write rules:</p>
|
||
|
||
<ul>
|
||
<li>Write a rule using Java</li>
|
||
<li>Write an XPath expression</li>
|
||
</ul>
|
||
|
||
<p>We’ll cover the Java way first and the XPath way second. Most of this documentation is applicable to both methods, too, so read on.</p>
|
||
|
||
<h2 id="figure-out-what-you-want-to-look-for">Figure out what you want to look for</h2>
|
||
|
||
<p>Lets’s figure out what problem we want to spot. We can use “While loops must use braces” as an example. In the source code below, it’s easy to get lost visually - it’s kind of hard to tell what the curly braces belong to.</p>
|
||
|
||
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Example</span> <span class="o">{</span>
|
||
<span class="kt">void</span> <span class="nf">bar</span><span class="o">()</span> <span class="o">{</span>
|
||
<span class="k">while</span> <span class="o">(</span><span class="n">baz</span><span class="o">)</span>
|
||
<span class="n">buz</span><span class="o">.</span><span class="na">doSomething</span><span class="o">();</span>
|
||
<span class="o">}</span>
|
||
<span class="o">}</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>So we know what an example in source code looks like, which is half the battle.</p>
|
||
|
||
<h2 id="write-a-test-data-example-and-look-at-the-ast">Write a test-data example and look at the AST</h2>
|
||
|
||
<p>PMD doesn’t use the source code directly; it uses a <code class="highlighter-rouge">JavaCC</code> generated parser to parse the source code and produce an AST (Abstract Syntax Tree). The AST for the code above looks like this:</p>
|
||
|
||
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CompilationUnit
|
||
TypeDeclaration
|
||
ClassDeclaration:(package private)
|
||
UnmodifiedClassDeclaration(Example)
|
||
ClassBody
|
||
ClassBodyDeclaration
|
||
MethodDeclaration:(package private)
|
||
ResultType
|
||
MethodDeclarator(bar)
|
||
FormalParameters
|
||
Block
|
||
BlockStatement
|
||
Statement
|
||
WhileStatement
|
||
Expression
|
||
PrimaryExpression
|
||
PrimaryPrefix
|
||
Name:baz
|
||
Statement
|
||
StatementExpression:null
|
||
PrimaryExpression
|
||
PrimaryPrefix
|
||
Name:buz.doSomething
|
||
PrimarySuffix
|
||
Arguments
|
||
</code></pre></div></div>
|
||
|
||
<p>You can generate this yourself by:</p>
|
||
|
||
<ul>
|
||
<li>Run the batch file <code class="highlighter-rouge">bin/designer.bat</code></li>
|
||
<li>Paste the code into the left text area and click the “Go” button</li>
|
||
<li>Note that there’s another panel and a textfield to test out XPath expressions; more on that later.</li>
|
||
<li>Here’s a screenshot: <figure><img class="docimage" src="images/devdocs/designer_screenshot.png" alt="Designer Screenshot" /></figure></li>
|
||
</ul>
|
||
|
||
<p>So you can see in the example above that the AST for a <code class="highlighter-rouge">WhileStatement</code> looks kind of like this (excluding that expression gibberish for clarity):</p>
|
||
|
||
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>WhileStatement
|
||
Expression
|
||
Statement
|
||
StatementExpression
|
||
</code></pre></div></div>
|
||
|
||
<p>If you were to add curly braces around the call to <code class="highlighter-rouge">buz.doSomething()</code> and click “Go” again, you’d see that the AST would change a bit. It’d look like this:</p>
|
||
|
||
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>WhileStatement
|
||
Expression
|
||
Statement
|
||
Block
|
||
BlockStatement
|
||
Statement
|
||
StatementExpression
|
||
</code></pre></div></div>
|
||
|
||
<p>Ah ha! We see that the curly braces add a couple more AST nodes - a <code class="highlighter-rouge">Block</code> and a <code class="highlighter-rouge">BlockStatement</code>. So all we have to do is write a rule to detect a <code class="highlighter-rouge">WhileStatement</code> that has a <code class="highlighter-rouge">Statement</code> that’s not followed by a <code class="highlighter-rouge">Block</code>, and we’ve got a rule violation.</p>
|
||
|
||
<p>By the way, all this structural information - i.e., the fact that a Statement may be followed a Block - is concisely defined in the <a href="https://github.com/pmd/pmd/blob/master/pmd-java/etc/grammar/Java.jjt">EBNF grammar</a>. So, for example, the Statement definition looks like this:</p>
|
||
|
||
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>void Statement() :
|
||
{}
|
||
{
|
||
LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement()
|
||
| LOOKAHEAD(2) LabeledStatement()
|
||
| Block()
|
||
| EmptyStatement()
|
||
| StatementExpression() ";"
|
||
| SwitchStatement()
|
||
| IfStatement()
|
||
| WhileStatement()
|
||
| DoStatement()
|
||
| ForStatement()
|
||
| BreakStatement()
|
||
| ContinueStatement()
|
||
| ReturnStatement()
|
||
| ThrowStatement()
|
||
| SynchronizedStatement()
|
||
| TryStatement()
|
||
}
|
||
</code></pre></div></div>
|
||
|
||
<p>showing that a Statement may be followed by all sorts of stuff.</p>
|
||
|
||
<h2 id="write-a-rule-class">Write a rule class</h2>
|
||
|
||
<p>Create a new Java class that extends <code class="highlighter-rouge">net.sourceforge.pmd.lang.java.rule.AbstractJavaRule</code>:</p>
|
||
|
||
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">net.sourceforge.pmd.lang.java.rule.*</span><span class="o">;</span>
|
||
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">WhileLoopsMustUseBracesRule</span> <span class="kd">extends</span> <span class="n">AbstractJavaRule</span> <span class="o">{</span>
|
||
<span class="o">}</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>That was easy. PMD works by creating the AST and then traverses it recursively so a rule can get a callback for any type it’s interested in. So let’s make sure our rule gets called whenever the AST traversal finds a <code class="highlighter-rouge">WhileStatement</code>:</p>
|
||
|
||
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">net.sourceforge.pmd.lang.java.rule.*</span><span class="o">;</span>
|
||
<span class="kn">import</span> <span class="nn">net.sourceforge.pmd.lang.java.ast.*</span><span class="o">;</span>
|
||
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">WhileLoopsMustUseBracesRule</span> <span class="kd">extends</span> <span class="n">AbstractJavaRule</span> <span class="o">{</span>
|
||
<span class="kd">public</span> <span class="n">Object</span> <span class="nf">visit</span><span class="o">(</span><span class="n">ASTWhileStatement</span> <span class="n">node</span><span class="o">,</span> <span class="n">Object</span> <span class="n">data</span><span class="o">)</span> <span class="o">{</span>
|
||
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"hello world"</span><span class="o">);</span>
|
||
<span class="k">return</span> <span class="n">data</span><span class="o">;</span>
|
||
<span class="o">}</span>
|
||
<span class="o">}</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>We stuck a <code class="highlighter-rouge">println()</code> in there for now so we can see when our rule gets hit.</p>
|
||
|
||
<h2 id="put-the-whileloopsmustusebracesrule-rule-in-a-ruleset-file">Put the WhileLoopsMustUseBracesRule rule in a ruleset file</h2>
|
||
|
||
<p>Now our rule is written - at least, the shell of it is - and now we need to tell PMD about it. We need to add it to a ruleset XML file. Look at <code class="highlighter-rouge">pmd-java/src/main/resources/category/java/bestpractices.xml</code>; it’s got lots of rule definitions in it. Copy and paste one of these rules into a new ruleset - call it <code class="highlighter-rouge">mycustomrules.xml</code> or something. Then fill in the elements and attributes:</p>
|
||
|
||
<ul>
|
||
<li>name - WhileLoopsMustUseBracesRule</li>
|
||
<li>message - Use braces for while loops</li>
|
||
<li>class - Wherever you put the rule. Note this doesn’t have to be in <code class="highlighter-rouge">net.sourceforge.pmd</code>; it can be in <code class="highlighter-rouge">com.yourcompany.util.pmd</code> or whereever you want</li>
|
||
<li>description - Use braces for while loops</li>
|
||
<li>example - A little code snippet in CDATA tags that shows a rule violation</li>
|
||
</ul>
|
||
|
||
<p>The whole ruleset file should look something like this:</p>
|
||
|
||
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?xml version="1.0"?></span>
|
||
<span class="nt"><ruleset</span> <span class="na">name=</span><span class="s">"My custom rules"</span>
|
||
<span class="na">xmlns=</span><span class="s">"http://pmd.sourceforge.net/ruleset/2.0.0"</span>
|
||
<span class="na">xmlns:xsi=</span><span class="s">"http://www.w3.org/2001/XMLSchema-instance"</span>
|
||
<span class="na">xsi:schemaLocation=</span><span class="s">"http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"</span><span class="nt">></span>
|
||
<span class="nt"><rule</span> <span class="na">name=</span><span class="s">"WhileLoopsMustUseBracesRule"</span>
|
||
<span class="na">message=</span><span class="s">"Avoid using 'while' statements without curly braces"</span>
|
||
<span class="na">class=</span><span class="s">"WhileLoopsMustUseBracesRule"</span><span class="nt">></span>
|
||
<span class="nt"><description></span>
|
||
Avoid using 'while' statements without using curly braces
|
||
<span class="nt"></description></span>
|
||
<span class="nt"><priority></span>3<span class="nt"></priority></span>
|
||
|
||
<span class="nt"><example></span>
|
||
<span class="cp"><![CDATA[
|
||
public void doSomething() {
|
||
while (true)
|
||
x++;
|
||
}
|
||
]]></span>
|
||
<span class="nt"></example></span>
|
||
<span class="nt"></rule></span>
|
||
<span class="nt"></ruleset></span>
|
||
</code></pre></div></div>
|
||
|
||
<h2 id="run-pmd-using-your-new-ruleset">Run PMD using your new ruleset</h2>
|
||
|
||
<p>OK, let’s run the new rule so we can see something work. Like this:</p>
|
||
|
||
<pre><code class="language-DOS">pmd.bat c:\path\to\my\src xml c:\path\to\mycustomrules.xml
|
||
</code></pre>
|
||
|
||
<p>This time your “hello world” will show up right after the AST gets printed out. If it doesn’t, post a message to <a href="http://sourceforge.net/p/pmd/discussion/188192">the forum</a> so we can improve this document :-)</p>
|
||
|
||
<h2 id="write-code-to-add-rule-violations-where-appropriate">Write code to add rule violations where appropriate</h2>
|
||
|
||
<p>Now that we’ve identified our problem, recognized the AST pattern that illustrates the problem, written a new rule, and plugged it into a ruleset, we need to actually make our rule find the problem, create a <code class="highlighter-rouge">RuleViolation</code>, and put it in the <code class="highlighter-rouge">Report</code>, which is attached to the <code class="highlighter-rouge">RuleContext</code>. Like this:</p>
|
||
|
||
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">net.sourceforge.pmd.lang.ast.*</span><span class="o">;</span>
|
||
<span class="kn">import</span> <span class="nn">net.sourceforge.pmd.lang.java.ast.*</span><span class="o">;</span>
|
||
<span class="kn">import</span> <span class="nn">net.sourceforge.pmd.lang.java.rule.*</span><span class="o">;</span>
|
||
|
||
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">WhileLoopsMustUseBracesRule</span> <span class="kd">extends</span> <span class="n">AbstractJavaRule</span> <span class="o">{</span>
|
||
<span class="kd">public</span> <span class="n">Object</span> <span class="nf">visit</span><span class="o">(</span><span class="n">ASTWhileStatement</span> <span class="n">node</span><span class="o">,</span> <span class="n">Object</span> <span class="n">data</span><span class="o">)</span> <span class="o">{</span>
|
||
<span class="n">Node</span> <span class="n">firstStmt</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="na">jjtGetChild</span><span class="o">(</span><span class="mi">1</span><span class="o">);</span>
|
||
<span class="k">if</span> <span class="o">(!</span><span class="n">hasBlockAsFirstChild</span><span class="o">(</span><span class="n">firstStmt</span><span class="o">))</span> <span class="o">{</span>
|
||
<span class="n">addViolation</span><span class="o">(</span><span class="n">data</span><span class="o">,</span> <span class="n">node</span><span class="o">);</span>
|
||
<span class="o">}</span>
|
||
<span class="k">return</span> <span class="kd">super</span><span class="o">.</span><span class="na">visit</span><span class="o">(</span><span class="n">node</span><span class="o">,</span><span class="n">data</span><span class="o">);</span>
|
||
<span class="o">}</span>
|
||
<span class="kd">private</span> <span class="kt">boolean</span> <span class="nf">hasBlockAsFirstChild</span><span class="o">(</span><span class="n">Node</span> <span class="n">node</span><span class="o">)</span> <span class="o">{</span>
|
||
<span class="k">return</span> <span class="o">(</span><span class="n">node</span><span class="o">.</span><span class="na">jjtGetNumChildren</span><span class="o">()</span> <span class="o">!=</span> <span class="mi">0</span> <span class="o">&&</span> <span class="o">(</span><span class="n">node</span><span class="o">.</span><span class="na">jjtGetChild</span><span class="o">(</span><span class="mi">0</span><span class="o">)</span> <span class="k">instanceof</span> <span class="n">ASTBlock</span><span class="o">));</span>
|
||
<span class="o">}</span>
|
||
<span class="o">}</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>TODO - if you don’t understand the code for the rule, post a message to <a href="http://sourceforge.net/p/pmd/discussion/188192">the forum</a> so we can improve this document :-)</p>
|
||
|
||
<h2 id="writing-a-rule-as-an-xpath-expression">Writing a rule as an XPath expression</h2>
|
||
|
||
<p>Daniel Sheppard integrated an XPath engine into PMD, so now you can write rules as XPath expressions. For example, the XPath expression for our WhileLoopsMustUseBracesRule looks like this:</p>
|
||
|
||
<p><code class="highlighter-rouge">//WhileStatement[not(Statement/Block)]</code></p>
|
||
|
||
<p>Concise, eh? Here’s an <a href="http://www.onjava.com/pub/a/onjava/2003/04/09/pmd_rules.html">article</a> with a lot more detail.</p>
|
||
|
||
<p>Note that for XPath rules you’ll need to set the <code class="highlighter-rouge">class</code> attribute in the rule definition to <code class="highlighter-rouge">net.sourceforge.pmd.lang.rule.XPathRule.</code> Like this:</p>
|
||
|
||
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><rule</span> <span class="na">name=</span><span class="s">"EmptyCatchBlock"</span>
|
||
<span class="na">message=</span><span class="s">"Avoid empty catch blocks"</span>
|
||
<span class="na">class=</span><span class="s">"net.sourceforge.pmd.lang.rule.XPathRule"</span><span class="nt">></span>
|
||
<span class="nt"><description></span>
|
||
etc., etc.
|
||
</code></pre></div></div>
|
||
|
||
<p>Note that access modifiers are held as attributes, so, for example,</p>
|
||
|
||
<p><code class="highlighter-rouge">//FieldDeclaration[@Private='true']</code></p>
|
||
|
||
<p>finds all private fields. You can see the code that determines all the attributes <a href="https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java">here</a></p>
|
||
|
||
<p>More information about writing XPath rules is <a href="pmd_userdocs_extending_writing_xpath_rules.html">available here</a>.</p>
|
||
|
||
<h2 id="i-need-some-kind-of-type-resolution-for-my-rule">I need some kind of Type Resolution for my rule!</h2>
|
||
|
||
<h3 id="inside-an-xpath-query">Inside an XPath query</h3>
|
||
|
||
<p>PMD’s XPath extensions include two functions called <code class="highlighter-rouge">typeIs</code> and <code class="highlighter-rouge">typeIsExactly</code>,
|
||
which determine if a node is of a specific type (either any subtype or exactly,
|
||
respectively).</p>
|
||
|
||
<p>Here a an example of use, inside an XPath query:</p>
|
||
|
||
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="sr">//</span><span class="no">ClassOrInterfaceDeclaration</span><span class="o">/</span><span class="no">ExtendsList</span><span class="o">/</span><span class="no">ClassOrInterfaceType</span><span class="p">[</span><span class="n">typeIs</span><span class="p">(</span><span class="s1">'junit.framework.TestCase'</span><span class="p">)]</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>This query will for instance match the following class declaration:</p>
|
||
|
||
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">junit.framework.TestCase</span><span class="o">;</span>
|
||
|
||
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Foo</span> <span class="kd">extends</span> <span class="n">TestCase</span> <span class="o">{</span> <span class="o">}</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>It will also match against classes which extend a <em>subtype</em> of <code class="highlighter-rouge">junit.framework.TestCase</code>,
|
||
i.e. a base class itself extending <code class="highlighter-rouge">TestCase</code> transitively. If you don’t want this behaviour,
|
||
then use <code class="highlighter-rouge">typeIsExactly</code> instead of <code class="highlighter-rouge">typeIs</code>.</p>
|
||
|
||
<p>Checking against an array type is possible with the double bracket syntax.
|
||
An array type is denoted by just appending <code class="highlighter-rouge">[]</code> to the fully qualified class name
|
||
of the component type. These can be repeated for arrays of arrays
|
||
(e.g. <code class="highlighter-rouge">byte[][]</code> or <code class="highlighter-rouge">java.lang.String[]</code>).</p>
|
||
|
||
<h3 id="with-java-code">With Java code</h3>
|
||
|
||
<p>Below an other sample of use of type resolution inside a java code:</p>
|
||
|
||
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
|
||
* A simple to detect the use of the class 'com.forbidden.class'.
|
||
*/</span>
|
||
<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"unchecked"</span><span class="o">)</span>
|
||
<span class="kd">public</span> <span class="n">Object</span> <span class="nf">visit</span><span class="o">(</span><span class="n">ASTClassOrInterfaceType</span> <span class="n">type</span><span class="o">,</span> <span class="n">Object</span> <span class="n">ruleCtx</span><span class="o">)</span> <span class="o">{</span>
|
||
<span class="n">Class</span> <span class="n">clazz</span> <span class="o">=</span> <span class="n">type</span><span class="o">.</span><span class="na">getType</span><span class="o">();</span>
|
||
<span class="k">if</span> <span class="o">(</span><span class="s">"com.forbidden.class"</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">clazz</span><span class="o">.</span><span class="na">getName</span><span class="o">()))</span> <span class="o">{</span>
|
||
<span class="n">addViolation</span><span class="o">(</span><span class="n">ruleCtx</span><span class="o">,</span><span class="n">type</span><span class="o">);</span>
|
||
<span class="o">}</span>
|
||
<span class="k">return</span> <span class="kd">super</span><span class="o">.</span><span class="na">visit</span><span class="o">(</span><span class="n">type</span><span class="o">,</span> <span class="n">ruleCtx</span><span class="o">);</span>
|
||
<span class="o">}</span>
|
||
</code></pre></div></div>
|
||
|
||
<blockquote>
|
||
<p>Note, that this will only work, if the auxiliary classpath for PMD is setup correctly, so that PMD can actually find the (compiled) class “com.forbidden.class” and you get the actual Class instance by calling getType().</p>
|
||
</blockquote>
|
||
|
||
<p>Otherwise, you’ll have to string-compare the image, e.g. <code class="highlighter-rouge">"com.forbidden.class".equals(node.getImage())</code></p>
|
||
|
||
<h2 id="thread-safety-concurrency-issues-and-reuse-of-rule-instances">Thread safety, concurrency issues and reuse of rule instances</h2>
|
||
|
||
<p>When executing the rule, PMD will instantiate a new instance of your rule. If PMD is executed in multiple threads, then each thread is using its own instance of the rule. This means, that the rule implementation <strong>does not need to care about threading issues</strong>, as PMD makes sure, that a single instance is not used concurrently by multiple threads.</p>
|
||
|
||
<p>However, for performance reasons, the rule instances are used for multiple files. This means, that the constructor of the rule is only executed once (per thread) and the rule instance is reused. If you rely on a proper initialization of instance properties, you can do the initialization e.g. in the visit-method of the <code class="highlighter-rouge">ASTCompilationUnit</code> AST node - which is visited as first node and only once per file. However, this solution would only work for rules written for the Java language. A language independent way is to override the method <code class="highlighter-rouge">apply</code> of the rule (and call super). The apply method is called exactly once per file.</p>
|
||
|
||
<p>If you want to share data across multiple files, see the above section “I want to implement a rule that analyze more than the class”.</p>
|
||
|
||
<h2 id="bundle-it-up">Bundle it up</h2>
|
||
|
||
<p>To use your rules as part of a nightly build or whatever, it’s helpful to bundle up both the rule and the ruleset.xml file in a jar file. Then you can put that jar file on the CLASSPATH of your build. Setting up a script or an Ant task to do this can save you some tedious typing.</p>
|
||
|
||
<h2 id="repeat-as-necessary">Repeat as necessary</h2>
|
||
|
||
<p>I’ve found that my rules usually don’t work the first time, and so I have to go back and tweak them a couple times. That’s OK, if we were perfect programmers PMD would be useless anyhow :-).</p>
|
||
|
||
<p>As an acceptance test of sorts, I usually run a rule on the JDK 1.4 source code and make sure that a random sampling of the problems found are in fact legitimate rule violations. This also ensures that the rule doesn’t get confused by nested inner classes or any of the other oddities that appear at various points in the JDK source.</p>
|
||
|
||
<p>You’re rolling now. If you think a rule would benefit the Java development community as a whole, post a message to <a href="http://sourceforge.net/p/pmd/discussion/188192">the forum</a> so we can get the rule moved into one of the core rulesets.</p>
|
||
|
||
<p>Or, if you can improve one of the existing rules, that’d be great too! Thanks!</p>
|
||
|
||
<p>Finally, for many more details on writing rules, pick up <a href="http://pmdapplied.com/">PMD Applied</a>!</p>
|
||
|
||
|
||
<div class="tags">
|
||
|
||
<b>Tags: </b>
|
||
|
||
|
||
|
||
<a href="tag_extending.html" class="btn btn-default navbar-btn cursorNorm" role="button">extending</a>
|
||
|
||
|
||
|
||
<a href="tag_userdocs.html" class="btn btn-default navbar-btn cursorNorm" role="button">userdocs</a>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
<hr class="shaded"/>
|
||
|
||
<footer>
|
||
<div class="row">
|
||
<div class="col-lg-12 footer">
|
||
©2019 PMD Open Source Project. All rights reserved. <br />
|
||
<span>Page last updated:</span> July 3, 2016<br/> Site last generated: Feb 8, 2019 <br />
|
||
<p><img src="images/pmd-logo-small.png" alt="Company logo"/></p>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
|
||
|
||
</div>
|
||
<!-- /.row -->
|
||
</div>
|
||
<!-- /.container -->
|
||
</div>
|
||
</div>
|
||
</body>
|
||
|
||
</html>
|