2018-06-16 20:39:36 +00:00
<!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 = "Writing XPath rules for PMD" >
< meta name = "keywords" content = "extendinguserdocs, " >
< title > Writing XPath rules | 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 XPath rules" > {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" >
2018-10-28 16:17:01 +00:00
< li class = "sidebarTitle" > PMD 6.10.0< / li >
2018-06-16 20:39:36 +00:00
< 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 >
2018-11-12 19:21:12 +00:00
< li > < a href = "pmd_next_major_development.html" > PMD 7.0.0 development< / a > < / li >
2018-06-16 20:39:36 +00:00
< 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 > < a href = "pmd_userdocs_extending_writing_pmd_rules.html" > Writing a rule< / a > < / li >
< li class = "active" > < 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_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 >
2018-08-08 06:36:04 +00:00
< li > < a href = "pmd_devdocs_pmdtester.html" > Pmdtester< / a > < / li >
2018-06-16 20:39:36 +00:00
< 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 XPath rules< / h1 >
< / div >
< div class = "post-content" >
< div class = "summary" > Writing XPath rules 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_xpath_rules.md" class = "btn btn-default githubEditButton" role = "button" > < i class = "fa fa-github fa-lg" > < / i > Edit me< / a >
< h1 id = "xpath-rule-tutorial" > XPath Rule tutorial< / h1 >
< div class = "alert alert-info" role = "alert" > < i class = "fa fa-info-circle" > < / i > < b > Note:< / b > For a translation to Georgian, see < a href = "http://webhostinggeeks.com/science/xpath-sourceforge-ka" > webhostinggeeks.com/science/xpath-sourceforge-ka< / a > < / div >
< p > Writing PMD rules with XPath can be a bit easier than writing rules with Java code. Here’ s an introduction on how to do that.< / p >
< h2 id = "introduction" > Introduction< / h2 >
< p > PMD provides a very handy method for writing rules by writing an XPath query. When the XPath query finds a match, a violation is added to the report. This document focuses on XPath rules. You can go < a href = "howtowritearule.html" > here< / a > for more information about writing a rule.< / p >
< h2 id = "what-is-the-abstract-syntax-tree-ast" > What is the Abstract Syntax Tree (AST)?< / h2 >
< p > From < a href = "http://foldoc.org/abstract+syntax+tree" > FOLDOC< / a > an AST is< / p >
< blockquote >
< p > A data structure representing something which has been parsed, often used as a compiler or interpreter’ s internal representation of a program while it is being optimised and from which code generation is performed.< / p >
< / blockquote >
< p > In our context, this means that we basically have a tree representation of the Java source file. This tree can viewed as a structured document - just like XML. And since it’ s conceptually similar to XML, it can be queried with XPath to find a pattern.< / p >
< h2 id = "using-designer" > Using Designer< / h2 >
< p > PMD comes with a handy tool that you will love if you want to write an XPath rule. Designer, runnable from a script in < code class = "highlighter-rouge" > bin/< / code > , is a very simple and useful utility for writing rules.< / p >
< p > The basic steps involved in writing XPath rules are these:< / p >
< ol >
< li > Write a simple Java example source snippet in Designer< / li >
< li > See the AST for the class you wrote< / li >
< li > Write an XPath expression that matches the violation you are searching< / li >
< li > Modify the Java class and go back to previous step to refine the XPath expression< / li >
< / ol >
< h2 id = "simple-xpath-expressions" > Simple XPath expressions< / h2 >
< p > This section provides hands-on examples of XPath queries over the AST. You will probably find this section more useful if you follow it with Designer and copy/paste the examples.< / p >
< p > Copy the following Java source code to Designer:< / p >
< div class = "language-java highlighter-rouge" > < div class = "highlight" > < pre class = "highlight" > < code > < span class = "kd" > public< / span > < span class = "kd" > class< / span > < span class = "nc" > a< / span > < span class = "o" > {< / span >
< span class = "kt" > int< / span > < span class = "n" > fOne< / span > < span class = "o" > ;< / span >
< span class = "kt" > int< / span > < span class = "n" > fTwo< / span > < span class = "o" > ;< / span >
< span class = "kd" > private< / span > < span class = "kt" > void< / span > < span class = "nf" > run< / span > < span class = "o" > ()< / span > < span class = "o" > {< / span >
< span class = "kt" > int< / span > < span class = "n" > one< / span > < span class = "o" > ;< / span >
< span class = "kt" > int< / span > < span class = "n" > two< / span > < span class = "o" > ;< / span >
< span class = "o" > }< / span >
< span class = "o" > }< / span >
< / code > < / pre > < / div > < / div >
< p > Let’ s assume you want to match something on class variable names. You see in the ASTVviewer that VariableDeclaratorId contains the variable name - in XML terms, the name is in the < code class = "highlighter-rouge" > @Image< / code > attribute. So you try an XPath expression as follows:< / p >
< p > < code class = "highlighter-rouge" > //VariableDeclaratorId< / code > < / p >
< p > If you try this expression you’ ll see that variables declared in methods are also matched. A more precise expression for matching field declarations is, well, using the FieldDeclaration node. This expression matches only the two fields declared in the class:< / p >
< p > < code class = "highlighter-rouge" > //FieldDeclaration< / code > < / p >
< p > In a similar way, you can match only local variables with this expression< / p >
< p > < code class = "highlighter-rouge" > //LocalVariableDeclaration< / code > < / p >
< p > With local variables we need to be more careful. Consider the following class:< / p >
< div class = "language-java highlighter-rouge" > < div class = "highlight" > < pre class = "highlight" > < code > < span class = "kd" > public< / span > < span class = "kd" > class< / span > < span class = "nc" > a< / span > < span class = "o" > {< / span >
< span class = "kd" > private< / span > < span class = "kt" > void< / span > < span class = "nf" > run< / span > < span class = "o" > ()< / span > < span class = "o" > {< / span >
< span class = "kd" > final< / span > < span class = "kt" > int< / span > < span class = "n" > one< / span > < span class = "o" > ;< / span >
< span class = "kt" > int< / span > < span class = "n" > two< / span > < span class = "o" > ;< / span >
< span class = "o" > {< / span >
< span class = "kt" > int< / span > < span class = "n" > a< / span > < span class = "o" > ;< / span >
< span class = "o" > }< / span >
< span class = "o" > }< / span >
< span class = "o" > }< / span >
< / code > < / pre > < / div > < / div >
< p > Local variable declarations will match ‘ a’ , since it is a perfectly legal Java local variable. Now, a more interesting expression is to match variables declared in a method, and not on an internal block, nor in the class. Maybe you’ ll start with an expression like this:< / p >
< p > < code class = "highlighter-rouge" > //MethodDeclaration//LocalVariableDeclaration< / code > < / p >
< p > You’ ll quickly see that all three local variables are matched. A possible solution for this is to request that the parent of the local variable declaration is the MethodDeclaration node:< / p >
< p > < code class = "highlighter-rouge" > //LocalVariableDeclaration[name(../../..) = 'MethodDeclaration']< / code > < / p >
< h2 id = "matching-variables-by-name" > Matching variables by name< / h2 >
< p > Let’ s consider that we are writing rules for logger. Let’ s assume we use the Java logging API and we want to find all classes that have more than one logger. The following expression returns all variable declarations whose type is ‘ Logger’ .< / p >
< p > < code class = "highlighter-rouge" > //VariableDeclarator[../Type/ReferenceType/ClassOrInterfaceType[@Image='Logger']]< / code > < / p >
< p > Finding a class with more than one logger is quite easy now. This expression matches the classes we are looking for.< / p >
< div class = "language-xpath highlighter-rouge" > < div class = "highlight" > < pre class = "highlight" > < code > < span class = "nt" > TypeDeclaration< / span > < span class = "p" > [< / span > < span class = "nf" > count< / span > < span class = "p" > (< / span > < span class = "o" > //< / span > < span class = "nt" > VariableDeclarator< / span > < span class = "p" > [..< / span > < span class = "o" > /< / span > < span class = "nt" > Type< / span > < span class = "o" > /< / span > < span class = "nt" > ReferenceType< / span > < span class = "o" > /< / span > < span class = "nt" > ClassOrInterfaceType< / span > < span class = "p" > [< / span > < span class = "na" > @Image< / span > < span class = "err" > =< / span > < span class = "s1" > 'Logger'< / span > < span class = "p" > ]])< / span > < span class = "o" > > < / span > < span class = "m" > 1< / span > < span class = "w" >
< / span > < / code > < / pre > < / div > < / div >
< p > But let’ s refine this expression a little bit more. Consider the following class:< / p >
< div class = "language-java highlighter-rouge" > < div class = "highlight" > < pre class = "highlight" > < code > < span class = "kd" > public< / span > < span class = "kd" > class< / span > < span class = "nc" > a< / span > < span class = "o" > {< / span >
< span class = "n" > Logger< / span > < span class = "n" > log< / span > < span class = "o" > =< / span > < span class = "kc" > null< / span > < span class = "o" > ;< / span >
< span class = "n" > Logger< / span > < span class = "n" > log< / span > < span class = "o" > =< / span > < span class = "kc" > null< / span > < span class = "o" > ;< / span >
< span class = "kt" > int< / span > < span class = "n" > b< / span > < span class = "o" > ;< / span >
< span class = "kt" > void< / span > < span class = "nf" > myMethod< / span > < span class = "o" > ()< / span > < span class = "o" > {< / span >
< span class = "n" > Logger< / span > < span class = "n" > log< / span > < span class = "o" > =< / span > < span class = "kc" > null< / span > < span class = "o" > ;< / span >
< span class = "kt" > int< / span > < span class = "n" > a< / span > < span class = "o" > ;< / span >
< span class = "o" > }< / span >
< span class = "kd" > class< / span > < span class = "nc" > c< / span > < span class = "o" > {< / span >
< span class = "n" > Logger< / span > < span class = "n" > a< / span > < span class = "o" > ;< / span >
< span class = "n" > Logger< / span > < span class = "n" > a< / span > < span class = "o" > ;< / span >
< span class = "o" > }< / span >
< span class = "o" > }< / span >
< / code > < / pre > < / div > < / div >
< p > With this class we will only be matching one violation, when we probably would have wanted to produce two violations (one for each class). The following refined expression matches classes that contain more than one logger.< / p >
< div class = "language-xpath highlighter-rouge" > < div class = "highlight" > < pre class = "highlight" > < code > < span class = "o" > //< / span > < span class = "nt" > ClassOrInterfaceBodyDeclaration< / span > < span class = "p" > [< / span > < span class = "nf" > count< / span > < span class = "p" > (< / span > < span class = "o" > //< / span > < span class = "nt" > VariableDeclarator< / span > < span class = "p" > [..< / span > < span class = "o" > /< / span > < span class = "nt" > Type< / span > < span class = "o" > /< / span > < span class = "nt" > ReferenceType< / span > < span class = "o" > /< / span > < span class = "nt" > ClassOrInterfaceType< / span > < span class = "p" > [< / span > < span class = "na" > @Image< / span > < span class = "err" > =< / span > < span class = "s1" > 'Logger'< / span > < span class = "p" > ]])< / span > < span class = "o" > > < / span > < span class = "m" > 1< / span > < span class = "p" > ]< / span > < span class = "w" >
< / span > < / code > < / pre > < / div > < / div >
< p > Let’ s assume we have a Factory class, that could be always declared final. We’ ll search an xpath expression that matches all declarations of Factory and reports a violation if it is not declared final. Consider the following class:< / p >
< div class = "language-java highlighter-rouge" > < div class = "highlight" > < pre class = "highlight" > < code > < span class = "kd" > public< / span > < span class = "kd" > class< / span > < span class = "nc" > a< / span > < span class = "o" > {< / span >
< span class = "n" > Factory< / span > < span class = "n" > f1< / span > < span class = "o" > ;< / span >
< span class = "kt" > void< / span > < span class = "nf" > myMethod< / span > < span class = "o" > ()< / span > < span class = "o" > {< / span >
< span class = "n" > Factory< / span > < span class = "n" > f2< / span > < span class = "o" > ;< / span >
< span class = "kt" > int< / span > < span class = "n" > a< / span > < span class = "o" > ;< / span >
< span class = "o" > }< / span >
< span class = "o" > }< / span >
< / code > < / pre > < / div > < / div >
< p > The following expression does the magic we need:< / p >
< div class = "language-xpath highlighter-rouge" > < div class = "highlight" > < pre class = "highlight" > < code > < span class = "o" > //< / span > < span class = "nt" > VariableDeclarator< / span > < span class = "w" >
< / span > < span class = "p" > [..< / span > < span class = "o" > /< / span > < span class = "nt" > Type< / span > < span class = "o" > /< / span > < span class = "nt" > ReferenceType< / span > < span class = "o" > /< / span > < span class = "nt" > ClassOrInterfaceType< / span > < span class = "w" >
< / span > < span class = "p" > [< / span > < span class = "na" > @Image< / span > < span class = "w" > < / span > < span class = "err" > =< / span > < span class = "w" > < / span > < span class = "s1" > 'Factory'< / span > < span class = "p" > ]< / span > < span class = "w" > < / span > < span class = "ow" > and< / span > < span class = "w" > < / span > < span class = "p" > ..[< / span > < span class = "na" > @Final< / span > < span class = "err" > =< / span > < span class = "s1" > 'false'< / span > < span class = "p" > ]]< / span > < span class = "w" >
< / span > < / code > < / pre > < / div > < / div >
< p > We recommend at this point that you experiment with Designer putting the final modifier to the Factory and verifying that the results produced are those expected.< / p >
< h2 id = "creating-a-new-rule-definition" > Creating a new rule definition< / h2 >
< p > To actually use your new XPath rule, it needs to be in a ruleset. You can create a new custom ruleset which just
contains your new XPath rule. You can use the following template. Just make sure, to replace the < code class = "highlighter-rouge" > xpath< / code > property,
the example code and give your rule a useful name and message.< / 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" > "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 >
2018-10-27 20:57:46 +00:00
< 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 >
2018-06-16 20:39:36 +00:00
< span class = "nt" > < description> < / span >
Custom rules
< span class = "nt" > < /description> < / span >
< span class = "nt" > < rule< / span > < span class = "na" > name=< / span > < span class = "s" > "My Rule"< / span >
< span class = "na" > language=< / span > < span class = "s" > "java"< / span >
< span class = "na" > message=< / span > < span class = "s" > "violation message"< / 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 >
Rule Description
< span class = "nt" > < /description> < / span >
< span class = "nt" > < priority> < / span > 3< span class = "nt" > < /priority> < / span >
< span class = "nt" > < properties> < / span >
< span class = "nt" > < property< / span > < span class = "na" > name=< / span > < span class = "s" > "xpath"< / span > < span class = "nt" > > < / span >
< span class = "nt" > < value> < / span > < span class = "cp" > < ![CDATA[
--- here comes your XPath expression
]]> < / span > < span class = "nt" > < /value> < / span >
< span class = "nt" > < /property> < / span >
< span class = "nt" > < /properties> < / span >
< span class = "nt" > < example> < / span >
< span class = "cp" > < ![CDATA[
public class ExampleCode {
public void foo() {
}
}
]]> < / span >
< span class = "nt" > < /example> < / span >
< span class = "nt" > < /rule> < / span >
< span class = "nt" > < /ruleset> < / span >
< / code > < / pre > < / div > < / div >
< p > Finally, for many more details on writing XPath 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" >
© 2018 PMD Open Source Project. All rights reserved. < br / >
2018-12-08 10:05:09 +00:00
< span > Page last updated:< / span > July 3, 2016< br / > Site last generated: Dec 8, 2018 < br / >
2018-06-16 20:39:36 +00:00
< p > < img src = "images/pmd-logo-small.png" alt = "Company logo" / > < / p >
< / div >
< / div >
< / footer >
< / div >
<!-- /.row -->
< / div >
<!-- /.container -->
< / div >
< / div >
< / body >
< / html >