-
Notifications
You must be signed in to change notification settings - Fork 8
/
writingchecks.html
1148 lines (937 loc) · 45.3 KB
/
writingchecks.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<!--
| Generated by Apache Maven Doxia Site Renderer 1.11.1 from src/xdocs/writingchecks.xml at 2024-12-12
| Rendered using Apache Maven Default Skin
-->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content="Apache Maven Doxia Site Renderer 1.11.1" />
<title>checkstyle – Writing Checks</title>
<link rel="stylesheet" href="./css/maven-base.css" />
<link rel="stylesheet" href="./css/maven-theme.css" />
<link rel="stylesheet" href="./css/site.css" />
<link rel="stylesheet" href="./css/print.css" media="print" />
<script type="text/javascript" src="./js/checkstyle.js"></script>
<script type="text/javascript"
src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript" src="./js/anchors.js"></script>
<script type="text/javascript" src="./js/google-analytics.js"></script>
<link rel="icon" href="./images/favicon.png" type="image/x-icon" />
<link rel="shortcut icon" href="./images/favicon.ico" type="image/ico" />
</head>
<body class="composite">
<div id="banner">
<a href="./" id="bannerLeft" title="Checkstyle"><img src="images/header-checkstyle-logo.png" alt="Checkstyle"/></a><a href="./" id="bannerRight" title="Checkstyle"><img src="images/header-right-ruller.png" alt="Checkstyle"/></a> <div class="clear">
<hr/>
</div>
</div>
<div id="breadcrumbs">
<div class="xright"><a href="" title="toTop">toTop</a> | <span id="publishDate">Last Published: 2024-12-12</span>
| <span id="projectVersion">Version: 10.21.0</span>
</div>
<div class="clear">
<hr/>
</div>
</div>
<div id="leftColumn">
<div id="navcolumn">
<h5>About</h5>
<ul>
<li class="none"><a href="index.html" title="Checkstyle">Checkstyle</a></li>
<li class="none"><a href="releasenotes.html" title="Release Notes">Release Notes</a></li>
<li class="none"><a href="consulting.html" title="Consulting">Consulting</a></li>
<li class="none"><a href="sponsoring.html" title="Sponsoring">Sponsoring</a></li>
</ul>
<h5>Documentation</h5>
<ul>
<li class="expanded"><a href="config.html" title="Configuration">Configuration</a>
<ul>
<li class="none"><a href="property_types.html" title="Property Types">Property Types</a></li>
<li class="none"><a href="config_system_properties.html" title="System Properties">System Properties</a></li>
</ul></li>
<li class="expanded"><a href="running.html" title="Running">Running</a>
<ul>
<li class="none"><a href="anttask.html" title="Ant Task">Ant Task</a></li>
<li class="none"><a href="cmdline.html" title="Command Line">Command Line</a></li>
</ul></li>
<li class="expanded"><a href="checks.html" title="Checks">Checks</a>
<ul>
<li class="collapsed"><a href="checks/annotation/index.html" title="Annotations">Annotations</a></li>
<li class="collapsed"><a href="checks/blocks/index.html" title="Block Checks">Block Checks</a></li>
<li class="collapsed"><a href="checks/design/index.html" title="Class Design">Class Design</a></li>
<li class="collapsed"><a href="checks/coding/index.html" title="Coding">Coding</a></li>
<li class="collapsed"><a href="checks/header/index.html" title="Headers">Headers</a></li>
<li class="collapsed"><a href="checks/imports/index.html" title="Imports">Imports</a></li>
<li class="collapsed"><a href="checks/javadoc/index.html" title="Javadoc Comments">Javadoc Comments</a></li>
<li class="collapsed"><a href="checks/metrics/index.html" title="Metrics">Metrics</a></li>
<li class="collapsed"><a href="checks/misc/index.html" title="Miscellaneous">Miscellaneous</a></li>
<li class="collapsed"><a href="checks/modifier/index.html" title="Modifiers">Modifiers</a></li>
<li class="collapsed"><a href="checks/naming/index.html" title="Naming Conventions">Naming Conventions</a></li>
<li class="collapsed"><a href="checks/regexp/index.html" title="Regexp">Regexp</a></li>
<li class="collapsed"><a href="checks/sizes/index.html" title="Size Violations">Size Violations</a></li>
<li class="collapsed"><a href="checks/whitespace/index.html" title="Whitespace">Whitespace</a></li>
</ul></li>
<li class="collapsed"><a href="filters/index.html" title="Filters">Filters</a></li>
<li class="collapsed"><a href="filefilters/index.html" title="File Filters">File Filters</a></li>
<li class="expanded"><a href="style_configs.html" title="Style Configurations">Style Configurations</a>
<ul>
<li class="none"><a href="google_style.html" title="Google's Style">Google's Style</a></li>
<li class="none"><a href="sun_style.html" title="Sun's Style">Sun's Style</a></li>
</ul></li>
</ul>
<h5>Developers</h5>
<ul>
<li class="expanded"><a href="extending.html" title="Extending Checkstyle">Extending Checkstyle</a>
<ul>
<li class="none"><strong>Writing Checks</strong></li>
<li class="none"><a href="writingjavadocchecks.html" title="Writing Javadoc Checks">Writing Javadoc Checks</a></li>
<li class="none"><a href="writingfilters.html" title="Writing Filters">Writing Filters</a></li>
<li class="none"><a href="writingfilefilters.html" title="Writing File Filters">Writing File Filters</a></li>
<li class="none"><a href="writinglisteners.html" title="Writing Listeners">Writing Listeners</a></li>
</ul></li>
<li class="none"><a href="contributing.html" title="Contributing">Contributing</a></li>
<li class="expanded"><a href="beginning_development.html" title="Beginning Development">Beginning Development</a>
<ul>
<li class="none"><a href="eclipse.html" title="Eclipse IDE">Eclipse IDE</a></li>
<li class="none"><a href="netbeans.html" title="NetBeans IDE">NetBeans IDE</a></li>
<li class="none"><a href="idea.html" title="IntelliJ IDE">IntelliJ IDE</a></li>
</ul></li>
<li class="none"><a href="apidocs/index.html" title="Javadoc">Javadoc</a></li>
</ul>
<h5>Project Documentation</h5>
<ul>
<li class="collapsed"><a href="project-info.html" title="Project Information">Project Information</a></li>
<li class="collapsed"><a href="project-reports.html" title="Project Reports">Project Reports</a></li>
</ul>
<a href="https://github.com/checkstyle/checkstyle" title="GitHub" class="poweredBy">
<img class="poweredBy" alt="GitHub" src="images/github_logo_social_coding_outlined.png" />
</a>
<a href="https://twitter.com/checkstyle_java/" title="Twitter" class="poweredBy">
<img class="poweredBy" alt="Twitter" src="images/twitter_button.png" />
</a>
<a href="https://stackoverflow.com/questions/tagged/checkstyle" title="Stackoverflow" class="poweredBy">
<img class="poweredBy" alt="Stackoverflow" src="images/stackoverflow.jpeg" />
</a>
<a href="https://groups.google.com/forum/#!forum/checkstyle" title="GoogleGroups" class="poweredBy">
<img class="poweredBy" alt="GoogleGroups" src="images/groups.png" />
</a>
<a href="https://www.ej-technologies.com/products/jprofiler/overview.html" title="JProfiler" class="poweredBy">
<img class="poweredBy" alt="JProfiler" src="https://www.ej-technologies.com/images/product_banners/jprofiler_medium.png" />
</a>
</div>
</div>
<div id="bodyColumn">
<div id="contentBox">
<section>
<h2><a name="Content"></a>Content</h2>
<ul>
<li><a href="#Content">Content</a></li>
<li><a href="#Overview">Overview</a></li>
<li><a href="#Writing_Checks">Writing Checks</a></li>
<li><a href="#Java_Grammar">Java Grammar</a></li>
<li><a href="#Printing_a_Java_tree_structure">Printing a Java tree structure</a></li>
<li><a href="#The_Checkstyle_SDK_Gui">The Checkstyle SDK Gui</a></li>
<li><a href="#Understanding_the_visitor_pattern">Understanding the visitor pattern</a></li>
<li><a href="#Visitor_in_action">Visitor in action</a></li>
<li><a href="#Understanding_token_sets">Understanding token sets</a></li>
<li><a href="#Comment_Tokens_in_AST">Comment Tokens in AST</a></li>
<li><a href="#Navigating_the_AST">Navigating the AST</a></li>
<li><a href="#Defining_Check_Properties">Defining Check Properties</a></li>
<li><a href="#Logging_violations">Logging violations</a></li>
<li><a href="#Integrating_Checks">Integrating Checks</a></li>
<li><a href="#Limitations">Limitations</a></li>
<li><a href="#Writing_FileSetChecks">Writing FileSetChecks</a></li>
<li><a href="#Declare_check.27s_external_resource_locations">Declare check's external resource locations</a></li>
<li><a href="#Huh.3F_I_can.27t_figure_it_out.21">Huh? I can't figure it out!</a></li>
<li><a href="#Contributing">Contributing</a></li></ul>
</section>
<section>
<h2><a name="Overview"></a>Overview</h2>
<p>
OK, so you have finally decided to write your own Check. Welcome
aboard! This is a really easy thing to do. Very basic Java knowledge is required
to write a Check. It is good practice even for students.
There are actually two different types of checks that can be made, each with
their own requirements. Before you start coding, you will have to find out
which kind of Check you want to implement.
</p>
<p>
The functionality of Checkstyle is implemented in modules that can
be plugged into Checkstyle. Modules can be containers for other
modules, i.e. they form a tree structure. The top level modules
that are known directly to the Checkstyle kernel (which is also a
module and forms the root of the tree) implement the
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/FileSetCheck.html">FileSetCheck</a>
interface. These are pretty simple to grasp: they take a set of
input files and fire violation messages.
</p>
<p>
Checkstyle provides a few FileSetCheck implementations by default.
One of them is the
<a href="apidocs/com/puppycrawl/tools/checkstyle/TreeWalker.html">TreeWalker</a>. A
TreeWalker supports submodules that are derived from the
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/AbstractCheck.html">AbstractCheck</a>
class. The TreeWalker operates by separately transforming each of
the Java input files into an abstract syntax tree and then handing
the result over to each of the Check submodules, which in turn have
a look at a certain aspect of the tree.
</p>
</section>
<section>
<h2><a name="Writing_Checks"></a>Writing Checks</h2>
<p>
Most of the functionality of Checkstyle is implemented as
Checks. If you know how to write your own Checks, you can extend
Checkstyle according to your needs without having to wait for the
Checkstyle development team. You are about to become a Checkstyle
Expert.
</p>
<p>
Suppose you have a convention that the number of methods in a
class should not exceed 30. This rule makes
sense. A class should only do one thing and do it well. With a
zillion methods chances are that the class does more than one
thing. The only problem you have is that your convention is not
checked by Checkstyle. You'll have to write your own Check
and plug it into the Checkstyle framework.
</p>
<p>
This chapter is organized as a tour that takes you
through the process of writing a Check step by step and explains both the theoretical
foundations and the
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/package-summary.html">Checkstyle
API</a> along the way.
</p>
</section>
<section>
<h2><a name="Java_Grammar"></a>Java Grammar</h2>
<p>
Every Java Program is structured into files, and each of these
files has a certain structure. For example, if there is a package statement,
it is always the first line of a file that is not comment or whitespace.
After the package statement comes a list of import statements, which
is followed by a class or interface definition, and so on.
</p>
<p>
If you have ever read an introductory level Java book, you probably
knew all of the above. And if you have studied computer science,
you probably also know that the rules that specify the Java language
can be formally specified using a grammar, though this statement is
simplified for didactic purposes.
</p>
<p>
There are tools which read a grammar definition and produce a parser
for the language that is specified in the grammar. In other
words, the output of the tool is a program that can transform a
stream of characters (a Java file) into a tree representation
that reflects the structure of the file (<a class="externalLink" href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">
an Abstract Syntax Tree or AST</a>).
Checkstyle uses the parser generator <a class="externalLink" href="https://www.antlr.org">ANTLR</a>,
but that is an implementation detail you do not need to worry about
when writing Checks, as this well tested parser will parse Java files
for you.
</p>
</section>
<section>
<h2><a name="Printing_a_Java_tree_structure"></a>Printing a Java tree structure</h2>
<p>
Checkstyle can print an AST for a java file. To do so, run
the checkstyle jar file with the <b>-t</b> or <b>-T</b> argument,
providing the java file.
</p>
<p>For example, take this MyClass.java file:</p>
<div class="source">
<pre>
/**
* My <b>class</b>.
* @see AbstractClass
*/
public class MyClass {
}
</pre></div>
<div class="wrapper">
<table border="0" class="bodyTable" style="table-layout: fixed;">
<tr class="a">
<td align="left">
1) Using -t as parameter.
<br />
java -jar checkstyle-X.XX-all.jar -t MyClass.java
</td>
<td>
2) Using -T as parameter.
<br />
java -jar checkstyle-X.XX-all.jar -T MyClass.java
</td>
</tr>
<tr class="b">
<td align="left">
<div class="source">
<pre>
CLASS_DEF -> CLASS_DEF [5:0]
|--MODIFIERS -> MODIFIERS [5:0]
| `--LITERAL_PUBLIC -> public [5:0]
|--LITERAL_CLASS -> class [5:7]
|--IDENT -> MyClass [5:13]
`--OBJBLOCK -> OBJBLOCK [5:21]
|--LCURLY -> { [5:21]
`--RCURLY -> } [7:0]
</pre></div>
</td>
<td>
<div class="source">
<pre>
CLASS_DEF -> CLASS_DEF [5:0]
|--MODIFIERS -> MODIFIERS [5:0]
| |--BLOCK_COMMENT_BEGIN -> /* [1:0]
| | |--COMMENT_CONTENT -> *\n * My <b>class</b>.\n * @see AbstractClass\n [1:2]
| | `--BLOCK_COMMENT_END -> */ [4:1]
| `--LITERAL_PUBLIC -> public [5:0]
|--LITERAL_CLASS -> class [5:7]
|--IDENT -> MyClass [5:13]
`--OBJBLOCK -> OBJBLOCK [5:21]
|--LCURLY -> { [5:21]
`--RCURLY -> } [7:0]
</pre></div>
</td>
</tr>
</table>
</div>
<p>
As you can see, a very small java file transforms to a huge Abstract Syntax Tree, because
this creates a very detailed tree that includes all components of the java file:
object blocks, comments, modifiers, etc.
</p>
</section>
<section>
<h2><a name="The_Checkstyle_SDK_Gui"></a>The Checkstyle SDK Gui</h2>
<p>
Still with us? Great, you have mastered the basic theory so here
is your reward - a GUI that displays the structure of a Java source file.
Run the gui with the command:
</p>
<div class="wrap-content">
<div class="source">
<pre>
java -cp checkstyle-${projectVersion}-all.jar com.puppycrawl.tools.checkstyle.gui.Main
</pre></div>
</div>
<p>
Click the button at the bottom of the frame
and select a syntactically correct Java source file. The frame
will be populated with a tree that corresponds to the structure
of the Java source code.
</p>
<p>
<span class="wrapper block">
<img src="images/gui_screenshot.png" alt="screenshot" />
</span>
</p>
<p>
In the leftmost column you can open and close branches
of the tree. The remaining columns display information about each node
in the tree. The second column displays a token type for each node. As
you navigate from the root of the tree to one of the leafs, you'll
notice that the token type denotes smaller and smaller units of your
source file, i.e. close to the root you might see the token type
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF">CLASS_DEF</a>
(a node that represents a class definition), while you will see token
types like IDENT (an identifier) near the leaves of the tree.
</p>
<p>
In the bottom of frame you can find buttons "Open File", "Reload File"
and a dropdown list with parse modes to choose. In the first option,
after choosing a file, a tree that corresponds to the java source
file is shown. Notice that only files with the ".java" extension
can be opened. The second option reloads the previously opened file from file system and
rebuilds the tree.
</p>
<p>
In the dropdown list next to "Modes" are three different
parse modes: "PLAIN JAVA", "JAVA WITH COMMENTS", "JAVA WITH JAVADOC AND COMMENTS".
"PLAIN JAVA" mode shows the AST corresponding to the java source code without comments. In
"JAVA WITH COMMENTS" you can also see comments blocks on the tree. Lastly, when
"JAVA WITH JAVADOC AND COMMENTS" is chosen the javadoc tree builds and attaches
to every comment block that contains javadoc.
</p>
<p>
Note: The text of a tree node and its children is selected automatically
after either pressing "Enter" or double-clicking on it. There is no
need to make a selection manually.
</p>
<p>
We'll get back to the details in the other columns later. They are important for
implementing Checks but not for understanding the basic concepts. For now, it is sufficient
to know that the gui is a tool that lets you look at the structure of a Java file, i.e. you
can see the Java grammar 'in action'.
</p>
<p> If you use <a class="externalLink" href="https://www.eclipse.org/">Eclipse</a> you can install the
<a class="externalLink" href="https://github.com/sevntu-checkstyle/checkstyle-ast-eclipse-viewer">
Checkstyle AST Eclipse Viewer</a>
plugin to launch that application from context menu on any file in Eclipse.
</p>
</section>
<section>
<h2><a name="Understanding_the_visitor_pattern"></a>Understanding the visitor pattern</h2>
<p>
Ready for a bit more theory? The last bit
that is missing before you can start writing Checks is understanding
the <a class="externalLink" href="https://en.wikipedia.org/wiki/Visitor_pattern">Visitor pattern</a>.
</p>
<p>
When working with an AST, a simple approach to writing Checks
on them would be to add a <code>check()</code> method to the class that defines
the AST nodes. For example, our AST type could have a method
<code>checkNumberOfMethods()</code>. Such an approach would suffer from a few
serious drawbacks. Most importantly, it does not provide an extensible
design, i.e. the Checks have to be known at compile time; there is no
way to write plugins.
</p>
<p>
Hence, Checkstyle's AST classes do not have any
methods that implement checking functionality. Instead,
Checkstyle's
<a href="apidocs/com/puppycrawl/tools/checkstyle/TreeWalker.html">TreeWalker</a>
takes a set of objects that extend the
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/AbstractCheck.html">AbstractCheck</a>
class. A Check provides methods that take an AST as an argument and
perform the checking process for that AST, most prominently
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/AbstractCheck.html#visitTokencom.puppycrawl.tools.checkstyle.api.DetailAST">
<code>visitToken()</code>
</a>.
</p>
<p>
It is important to understand that the individual
Checks do not drive the AST traversal (it is possible
to traverse the tree manually, but not recommended).
Instead, the TreeWalker traverses the tree using a
<a class="externalLink" href="https://en.wikipedia.org/wiki/Tree_traversal">tree traversal (depth-first)</a>
algorithm, and calls the Check's methods.
</p>
<p>
Before any visitor method is called, the TreeWalker will call
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/AbstractCheck.html#beginTreecom.puppycrawl.tools.checkstyle.api.DetailAST">
<code>beginTree</code>
</a> to give the Check a chance to do
some initialization. Then, when performing the traversal from
the root to the leaf nodes, the <code>visitToken()</code>
method is called. Unlike the basic examples in the pattern book, there
is a <code>visitToken()</code> counterpart called
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/AbstractCheck.html#leaveTokencom.puppycrawl.tools.checkstyle.api.DetailAST">
<code>leaveToken</code>
</a>. The TreeWalker will call that
method to signal that the subtree below the node has been processed and
the TreeWalker is backtracking from the node. After the root node has
been left, the TreeWalker will call
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/AbstractCheck.html#finishTreecom.puppycrawl.tools.checkstyle.api.DetailAST">
<code>finishTree</code>
</a>.
</p>
</section>
<section>
<h2><a name="Visitor_in_action"></a>Visitor in action</h2>
<p>
Let's get back to our example and start writing code - that's why
you came here, right? Remember that we are in the process of
writing a check that limits the amount of methods in a class.
Firing up the Checkstyle GUI and looking at a few source
files, we notice that we are interested in the
number of tree nodes of type METHOD_DEF. The number of such tokens
should be counted separately for each CLASS_DEF / INTERFACE_DEF.
</p>
<p>
Hence, we need to register the Check for the token types
CLASS_DEF and INTERFACE_DEF. The TreeWalker will only call
visitToken for these token types. Because the requirements of
our tasks are so simple, there is no need to implement the other
methods (<code>leaveToken()</code>, <code>finishTree()</code>, etc.)
available to us from AbstractCheck. Here is our first shot at our
Check implementation:
</p>
<div class="source">
<pre>
package com.mycompany.checks;
import com.puppycrawl.tools.checkstyle.api.*;
public class MethodLimitCheck extends AbstractCheck
{
private static final int DEFAULT_MAX = 30;
private int max = DEFAULT_MAX;
@Override
public int[] getDefaultTokens()
{
return new int[]{TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF};
}
@Override
public void visitToken(DetailAST ast)
{
// find the OBJBLOCK node below the CLASS_DEF/INTERFACE_DEF
DetailAST objBlock = ast.findFirstToken(TokenTypes.OBJBLOCK);
// count the number of direct children of the OBJBLOCK
// that are METHOD_DEFS
int methodDefs = objBlock.getChildCount(TokenTypes.METHOD_DEF);
// report violation if limit is reached
if (methodDefs > this.max) {
String message = "too many methods, only " + this.max + " are allowed";
log(ast.getLineNo(), message);
}
}
}
</pre></div>
</section>
<section>
<h2><a name="Understanding_token_sets"></a>Understanding token sets</h2>
<p>
There are four methods in Check class to control the processed
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html">TokenTypes</a> -
one setter
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/AbstractCheck.html#setTokens-java.lang.String...-">
setTokens()</a>, which is used to define a custom set (which is different
from the default one) of the processed TokenTypes via config file and
three getters, which have to be overridden:
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/AbstractCheck.html#getDefaultTokens--">
getDefaultTokens()</a>,
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/AbstractCheck.html#getAcceptableTokens--">
getAcceptableTokens()</a>,
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/AbstractCheck.html#getRequiredTokens--">
getRequiredTokens()</a>.
</p>
<ul>
<li>
getDefaultTokens() - returns a set of TokenTypes which are processed in the
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/AbstractCheck.html#visitToken-com.puppycrawl.tools.checkstyle.api.DetailAST-">
visitToken()</a> method by default.
</li>
<li>
getRequiredTokens() - returns a set of TokenTypes which Check must be subscribed to for
a valid execution. If the user wants to specify a custom set of TokenTypes then
this set must contain all the TokenTypes from RequiredTokens.
</li>
<li>
getAcceptableTokens() - returns a set, which contains all the TokenTypes that
can be processed by the check. Both DefaultTokens and RequiredTokens and any custom
set of TokenTypes are subsets of AcceptableTokens.
</li>
</ul>
</section>
<section>
<h2><a name="Comment_Tokens_in_AST"></a>Comment Tokens in AST</h2>
<p>
Before <a href="releasenotes_old_6-0_7-8.html#Release_6.0">Checkstyle 6.0</a>,
there were no comments in the AST. Comments are not code and are ignored by compiler,
so they were not the primary focus of Checkstyle,
but more and more requests appeared to do validation of javadoc and comments.
One simple solution was to receive the plain-text of the file in a Check, manually parse
it for any custom comments and validation.
</p>
<p>
In version 6.0, a method was added to the AbstractCheck class which allows you to see
comment nodes in the AST -
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/AbstractCheck.html#isCommentNodesRequired--">
isCommentNodesRequired()</a>. When this returns `true`, comments are included
in the AST alongside the code.
</p>
<p>
This feature is optional to maintain backwards compatibility with existing checks,
as it changes the AST structure and many existing checks were not ready for this change.
Checkstyle does not parse the files twice to include the comments.
Comments were already in the grammar and parsed, but skipped
during the creation of AST nodes.
</p>
<p>
Before execution, all Checks are divided into 2 groups (based on the isCommentNodesRequired
method): "PLAIN JAVA" and "JAVA WITH COMMENTS".
Checkstyle executes "java only Checks" first. When those checks are all finished,
Checkstyle appends the comment AST nodes to the AST and calls "comment Checks".
All Javadoc Checks that are a child of
<a href="apidocs/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheck.html">
<code>AbstractJavadocCheck</code>
</a>are "comment Checks".
(See also <a href="writingjavadocchecks.html">'Writing Javadoc Checks'</a>)
</p>
<p>
The following Comment specific tokens exist:
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#SINGLE_LINE_COMMENT">
SINGLE_LINE_COMMENT</a>,
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BLOCK_COMMENT_BEGIN">
BLOCK_COMMENT_BEGIN</a>,
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BLOCK_COMMENT_END">
BLOCK_COMMENT_END</a>,
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#COMMENT_CONTENT">
COMMENT_CONTENT</a>.
</p>
</section>
<section>
<h2><a name="Navigating_the_AST"></a>Navigating the AST</h2>
<p>
In the example above you already saw that the DetailsAST class
provides utility methods to extract information from the tree,
like <code>getChildCount()</code>. By now you have
probably consulted the API documentation - and if not, you should -
and found that
<a class="externalLink" href="https://github.com/checkstyle/checkstyle/blob/master/src/main/java/com/puppycrawl/tools/checkstyle/api/DetailAST.java">
DetailsAST</a> additionally provides methods for navigating around
in the syntax tree, like finding the next sibling of a node, the
children of a node, the parent of a node, etc.
</p>
<p>
These methods provide great power for developing complex
Checks. Most of the Checks that Checkstyle provides by default
use these methods to analyze the environment of the ASTs that
are visited by the TreeWalker. Don't abuse that feature for
exploring the whole tree, though. Let the TreeWalker drive the
tree traversal and limit the visitor to the neighbours of a
single AST node.
</p>
</section>
<section>
<h2><a name="Defining_Check_Properties"></a>Defining Check Properties</h2>
<p>
OK Mr. Checkstyle, that's all very nice, but in my company we
have several projects, and each has another number of allowed
methods. I need to control my Check through properties, so where
is the API to do that?
</p>
<p>
Well, the short answer is, there is no API. It's magic. Really!
</p>
<p>
If you need to make something configurable, just add a setter method
to the Check:
</p>
<div class="source">
<pre>
public class MethodLimitCheck extends AbstractCheck
{
// code from above omitted for brevity
public void setMax(int limit)
{
max = limit;
}
}
</pre></div>
<p>
With this code added, you can set the property <code>max</code> for the
MethodLimitCheck module in the configuration file. It doesn't get any
simpler than that. The secret is that Checkstyle uses
<a class="externalLink" href="https://docs.oracle.com/javase/tutorial/reflect/member/fieldValues.html">
JavaBean reflection</a> to set the JavaBean properties. This works for all
primitive types (for example boolean, int, and long), Strings, and arrays of these types.
</p>
</section>
<section>
<h2><a name="Logging_violations"></a>Logging violations</h2>
<p>
Detecting violations is one thing. Presenting them to the user is
another. To do that, the Check base class provides several log
methods, the simplest of them being <code>Check.log(String)</code>. In your
Check you can simply use a verbatim violation string as the argument, i.e.
<code>log("Too many methods, only " + mMax +
" are allowed");</code>. This will
work, but it's not the best possible solution if your Check is
intended for a wider audience.
</p>
<p>
If you are not living in a country where people speak English,
you may have noticed that Checkstyle writes internationalized
violation messages. For example, if you live in Germany the violation,
messages are German. The individual Checks don't have to do
anything fancy to achieve this. It's actually quite easy and the
Checkstyle framework does most of the work.
</p>
<p>
To support internationalized violation messages, you need to create or reuse an existing
messages.properties file alongside your Check class (
<a class="externalLink" href="https://github.com/checkstyle/checkstyle/blob/master/src/main/resources/com/puppycrawl/tools/checkstyle/checks/sizes/messages.properties">
example</a>).
The Java file and the properties files should be in the same
directory. Add a symbolic violation code and an English
representation to the messages.properties. The file should
contain the following line: <code>too.many.methods=Too many methods, only {0} are
allowed</code>. Then replace the verbatim violation message with
the symbolic representation and use one of the log helper
methods to provide the dynamic part of the message (mMax in this
case): <code>log("too.many.methods",
mMax);</code>. Please consult the documentation of Java's
<a class="externalLink" href="https://docs.oracle.com/javase/8/docs/api/java/text/MessageFormat.html">
MessageFormat</a>
to learn about the syntax of format strings (especially about
those funny numbers in the translated text).
</p>
<p>
Supporting a new language is very easy now. Simply create a new
messages file for the language, e.g. messages_fr.properties to
provide French violation messages. The correct file will be chosen
automatically, based on the language settings of the user's
operating system.
</p>
</section>
<section>
<h2><a name="Integrating_Checks"></a>Integrating Checks</h2>
<p>
The great final moment has arrived! You are about to run your
Check. To integrate your Check, add a new subentry under the
TreeWalker module of your configuration file. Use the full
classname of your Check class as the name of the module.
Your configuration file <code>config.xml</code> should look something like this:
</p>
<div class="source">
<pre>
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="TreeWalker">
<!-- your standard Checks that come with Checkstyle -->
<module name="UpperEll"/>
<module name="MethodLength"/>
<!-- your Check goes here -->
<module name="com.mycompany.checks.MethodLimitCheck">
<property name="max" value="45"/>
</module>
</module>
</module>
</pre></div>
<p>
To run the new Check on the command line compile your Check,
create a jar that contains the classes and property files,
e.g. <code>mycompanychecks.jar</code>. Then run
(with the path separator
<a class="externalLink" href="https://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html">
system property ("path.separator")</a> adjusted to your platform:
Linux/Unix - ":", Windows - ";"):
</p>
<p>For Linux/Unix OS:</p>
<div class="wrap-content">
<div class="source">
<pre>
java -classpath mycompanychecks.jar:checkstyle-${projectVersion}-all.jar \
    com.puppycrawl.tools.checkstyle.Main -c config.xml myproject
</pre></div>
</div>
<p>For Windows OS:</p>
<div class="wrap-content">
<div class="source">
<pre>
java -classpath mycompanychecks.jar;checkstyle-${projectVersion}-all.jar ^
    com.puppycrawl.tools.checkstyle.Main -c config.xml myproject
</pre></div>
</div>
<p>
Did you see all those violations about "too many methods"
flying over your screen? Congratulations. You can now consider
yourself a Checkstyle expert. Go to your fridge. Have a beer.
</p>
<p>
Please consult the <a href="config.html#Packages">Checkstyle
configuration manual</a> to learn how to integrate your Checks
into the package configuration so that you can use <code>MethodLimit</code> instead of the
full class name.
</p>
</section>
<section>
<h2><a name="Limitations"></a>Limitations</h2>
<p>
There are only a few, but important, limitations for Checkstyle. These pertain to Java
specifically, as well as regular text files.
</p>
<p>
For Java,
</p>
<ul>
<li>
Code has to be compilable by <code>javac</code> to get valid violations.
If it is not, you can get hard to understand parse errors.
</li>
<li>
Java
<a class="externalLink" href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.5">
tokens (identifiers, keywords)</a>
should be written with
<a class="externalLink" href="https://en.wikipedia.org/wiki/Unicode">Unicode</a>
characters ONLY,
no
<a class="externalLink" href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.3">
Unicode escape sequence </a>
support (i.e. <code>\uXXXX</code>) in keywords and identifiers.
</li>
<li>Javadoc comments are limited to
<a class="externalLink" href="https://en.wikipedia.org/wiki/ASCII">ASCII</a> characters until
<a class="externalLink" href="https://github.com/checkstyle/checkstyle/issues/10629">
Issue #10629.</a>
</li>
<li>You cannot determine the type of an expression.
Example: "getValue() + getValue2()"</li>
<li>You cannot determine the full inheritance hierarchy of type.</li>
</ul>
<p>
In addition to Java files, there are similar limitations that apply to all
type of text files:
</p>
<ul>
<li>
Checkstyle cannot properly handle a file's binary
<a class="externalLink" href="https://en.wikipedia.org/wiki/Byte_order_mark">
Byte Order Mark (BOM)</a>, like UTF8's Unicode \uFEFF.
</li>
<li>
You cannot see the contents of other files. You have access to the
content of one file only during all Checks execution. All files
are processed one by one.
</li>
</ul>
<p>
This means that you cannot implement some code inspection
features that are available in advanced IDEs like Eclipse,
<a class="externalLink" href="https://www.jetbrains.com/idea/">IntelliJ IDEA</a>,
<a class="externalLink" href="https://spotbugs.github.io/">SpotBugs</a>,
<a class="externalLink" href="https://www.sonarsource.com/products/sonarqube/">Sonarqube</a>.
</p>
<p>
For example you will not be able to implement:
<br />
- a Check that finds redundant type casts or unused public methods.
<br />
- a Check that validate that user custom Exception class inherited from
java.lang.Exception class.
</p>
</section>
<section>
<h2><a name="Writing_FileSetChecks"></a>Writing FileSetChecks</h2>
<p>Writing a FileSetCheck is usually required when you do not need to parse Java files
to access the inner structure, or you are going to validate non "*.java" files.
</p>
<p>
Writing a FileSetCheck is pretty straightforward! Just inherit from
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/AbstractFileSetCheck.html">
AbstractFileSetCheck</a> and override the abstract
<a href="apidocs/com/puppycrawl/tools/checkstyle/api/AbstractFileSetCheck.html#processFiltered-java.io.File-com.puppycrawl.tools.checkstyle.api.FileText-">
<code>processFiltered(java.io.File, java.util.List)</code>
</a> method and you're done. A very simple example could fire a violation if the number
of files exceeds a certain limit. Here is a FileSetCheck that does just that:
</p>