forked from eisop/checker-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdeveloper-manual.html
More file actions
767 lines (632 loc) · 29.5 KB
/
developer-manual.html
File metadata and controls
767 lines (632 loc) · 29.5 KB
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
<!DOCTYPE html>
<html>
<head>
<title>Checker Framework developer manual</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="../manual/favicon-checkerframework.png" type="image/png"/>
</head>
<body>
<h1 id="Checker_Framework_developer_manual">Checker Framework developer manual</h1>
<p>
If you wish to use the Checker Framework, see its user manual
(<a href="https://eisop.github.io/cf/manual/">HTML</a>,
<a href="https://eisop.github.io/cf/manual/checker-framework-manual.pdf">PDF</a>).
</p>
<p>
This document contains information for Checker Framework developers,
including people who wish to edit its source code or make pull requests.
</p>
<p>Contents:</p>
<!-- start toc. do not edit; run html-update-toc instead -->
<ul>
<li><a href="#Directory_structure">Directory structure</a>
<ul>
<li><a href="#Related_repositories">Related repositories</a></li>
</ul></li>
<li><a href="#Build_tasks">Build tasks</a></li>
<li><a href="#tests">Testing the Checker Framework</a>
<ul>
<li><a href="#testing-optimizations">Testing optimizations</a></li>
</ul></li>
<li><a href="#code-style">Code style</a></li>
<li><a href="#IDE_configuration">IDE configuration</a></li>
<li><a href="#pull-requests">Pull requests</a>
<ul>
<li><a href="#pull-requests-branches">Branches</a></li>
<li><a href="#pull-requests-maintainers">Pull request and commit notes for maintainers</a></li>
</ul></li>
<li><a href="#github-configuration">GitHub configuration</a></li>
<li><a href="#ci">Continuous Integration</a>
<ul>
<li><a href="#ci-github-actions">GitHub Actions</a></li>
<li><a href="#ci-azure-pipelines">Azure Pipelines</a>
<ul>
<li><a href="#ci-increasing-quota">Increasing quota</a></li>
<li><a href="#project-visibility">How to change project visibility settings</a></li>
</ul></li>
<li><a href="#ci-travis">Travis CI</a></li>
<li><a href="#ci-failure">Reproducing Continuous Integration build failures</a></li>
</ul></li>
<li><a href="#Documenting_refactoring_ideas">Documenting refactoring ideas</a></li>
<li><a href="#annotated-library-version-numbers">Version numbers for annotated libraries</a></li>
<li><a href="#Making_a_Checker_Framework_release">Making a Checker Framework release</a></li>
<li><a href="#Supporting_a_new_version_of_Java">Supporting a new version of Java</a></li>
<li><a href="#Case_studies">Describing a case study</a></li>
<li><a href="#Counting_annotations">Counting annotations</a></li>
<li><a href="#Build_historical">Building a historical version of the Checker Framework</a></li>
</ul>
<!-- end toc -->
<h2 id="Directory_structure">Directory structure</h2>
<p>
The <a href="https://github.com/eisop/checker-framework">checker-framework
repository</a> contains several related projects:
</p>
<dl>
<dt><code>framework</code></dt>
<dd>the framework that enables building pluggable type checkers</dd>
<dt><code>checker</code></dt>
<dd>the type checkers provided with the Checker Framework</dd>
<dt><code>javacutil</code></dt>
<dd>utilities for integrating with javac</dd>
<dt><code>dataflow</code></dt>
<dd>a dataflow framework that is used by the Checker Framework, <a href="https://errorprone.info">Error Prone</a>, <a href="https://github.com/uber/NullAway">NullAway</a>, and other tools</dd>
</dl>
<p>
The repository also contains the following directories:
</p>
<dl>
<dt><code>docs</code></dt>
<dd>documentation: manual, tutorial, examples, developer docs</dd>
</dl>
<h3 id="Related_repositories">Related repositories</h3>
<p>
The <a href="https://github.com/eisop/checker-framework"><code>checker-framework</code></a> project
depends on
the <a href="https://github.com/eisop/jdk"><code>eisop/jdk</code></a> project,
the <a href="https://github.com/eisop/annotation-tools"><code>annotation-tools</code></a> project,
and the <a href="https://github.com/eisop/stubparser"><code>stubparser</code></a> project.
When making changes to one of these projects, you may also need to make changes to one or more of the others.
</p>
<p>
If you make related changes in the <code>checker-framework</code> and <code>jdk</code>
repositories, use the <em>same
branch name</em> for each. The continuous integration framework will find
and use that branch when running tests.
For example, when continuous integration runs for branch <em>B</em> of fork <em>F</em> of <code>checker-framework</code>, it will use branch <em>B</em> of fork <em>F</em> of the other repositories (if they exist).
The same is true for the other projects.
</p>
<p>
You do not need to explicitly build the <code>jdk</code> repository. Building
the Checker Framework (say, via <code>./gradlew assemble</code>) automatically
makes the Checker Framework use the annotated JDK that exists
at <code>../jdk/</code> — that is, as a sibling directory of the Checker
Framework named <code>jdk</code>.
</p>
<p>
If a change spans multiple projects, make pull requests for all of them.
Each pull request description's should link to all the others.
</p>
<p>
Furthermore, whenever you make a pull request from
a <code>checker-framework</code> branch A into branch B, if B has a
corresponding <code>jdk</code>
branch, then A also needs one.
A needs the branch even if A's branch is identical to B's; in that case,
beware of a <a href="#azure-pipelines-bug-same-commit-hash">bug in Azure Pipelines</a>.
</p>
<h2 id="Build_tasks">Build tasks</h2>
<p>
Full instructions for building the Checker Framework from sources appear in
the <a href="https://eisop.github.io/cf/manual/#build-source">Checker
Framework manual</a>. This section describes the build system (the Gradle build tasks).
</p>
<p>
Don't run the <code>gradle</code> command, which would use whatever version
of Gradle is installed on your computer. Instead, use
the <code>gradlew</code> script in the <code>checker-framework</code>
directory, also known as
the <a href="https://docs.gradle.org/current/userguide/gradle_wrapper.html">Gradle
wrapper</a>.
</p>
<p>
Frequently-used tasks:
</p>
<ul>
<li> <code>assemble</code>: builds all artifacts, including jars and Javadoc jars.
<li> <code>assembleForJavac</code>: builds only the jars required to use <code>checker/bin/javac</code>; faster than <code>assemble</code>.
<li> <code>build</code>: <code>assemble</code>, plus runs all JUnit tests.
<li> <code>allTests</code>: runs all tests.
<li> <code>spotlessApply</code>: reformats Java files.
<li> <code>spotlessCheck</code>: checks formatting of Java files.
<li> <code><em>NameOfJUnitTest</em></code>: runs the JUnit test with that name; for example, <code>NullnessTest</code>.
<li> <code>task</code>: lists tasks; use <code>--all</code> to see all tasks.
</ul>
<p>
If you run a task from the main directory, then it will run that task in all
subprojects with a task by that name. So, if you run <code>./gradlew
allTests</code> that runs all tests everywhere. But <code>(cd
framework && ../gradlew allTests)</code> only runs tests in
the <code>framework</code> project.
Alternatively, running <code>:framework:allTests</code> from the
main directory or any subproject runs the <code>allTests</code> task only in the <code>framework</code> project.
</p>
<p>
An iterative build-test-debug cycle where you assemble the Checker Framework
and execute its tests can sometimes lead to a state where Gradle is not able to
compile and build the system for no obvious reason.
This is especially common when you kill tests before they fully finish, or kill
compilation before it is fully complete, leading to a bad state or an
inconsistent build cache.
</p>
<p>
Below are some steps you might try to resolve this issue (in order):
</p>
<ul>
<li><code>./gradlew --no-build-cache assemble</code>: attempts to rebuild the Checker Framework without the build cache.
<li>Kill any Gradle daemons; run <code>./gradlew --status</code> to get a list of pids for Gradle.
<li><code>git clean -fdx</code>: removes all files that are not under version control. <b>Add or stash files that you would like to
keep before running this command</b>.
<li>Delete the Gradle build cache, usually located at <code>~/.gradle/caches</code>. Note: this will delete the entire build
cache, including the cache for other Gradle projects on your machine; the build step for the Checker Framework will need to re-download all required dependencies.
</ul>
<h2 id="tests">Testing the Checker Framework</h2>
<p>
For writing new test cases, see file <a href="https://raw.githubusercontent.com/eisop/checker-framework/master/checker/tests/README"><code>checker/tests/README</code></a>.
</p>
<h3 id="testing-optimizations">Testing optimizations</h3>
<p>
To test an optimization that should speed up type-checking, see
the <code>test-daikon.sh</code> stage of the <code>daikon_jdk*</code> job
of the Azure Pipelines CI job. Compare the run time of this stage (or of
the entire <code>daikon_jdk*</code> job) between the master branch and a
branch with your improvements.
</p>
<p>
You can also compare run times of the Checker Framework test suite.
</p>
<h2 id="code-style">Code style</h2>
<p>
Code in this project follows the
<a href="https://google.github.io/styleguide/javaguide.html">Google Java Style
Guide</a>,
<a href="https://homes.cs.washington.edu/~mernst/advice/coding-style.html">Michael
Ernst's coding style guidelines</a>, and <a href="https://www.oracle.com/java/technologies/javase/codeconventions-indentation.html#248">Oracle's
Java code conventions</a>.
</p>
<p>
From the command line, you can format your code by running <code>./gradlew spotlessApply</code>.
You
can <a href="https://github.com/google/google-java-format#using-the-formatter">configure
your IDE</a> (Eclipse or IntelliJ) to use the formatting.
</p>
<p>
We don't use <code>@author</code> Javadoc tags in code files.
Doing so clutters the code, and is misleading once that individual
is no longer maintaining the code.
Authorship (and who has made changes recently) can be obtained from the
version control system, such as by running <code>git annotate <em>filename</em></code>.
</p>
<p>
Every class, method, and field (even private ones) must have a
descriptive Javadoc comment.
</p>
<p>
If a nested class has a very common and generic name, do
not <code>import</code> it. In code, write the outer and inner class name
(as in <code>Tree.Kind</code> or <code>Map.Entry</code>) rather than just
the simple name <code>Kind</code> or <code>Entry</code>.
</p>
<p>
Use <code>/*package-private*/</code> to explicitly mark package-private elements.
</p>
<h2 id="IDE_configuration">IDE configuration</h2>
<p>
First clone and build all projects from their sources, from the command line,
using the instructions
at <a href="https://eisop.github.io/cf/manual/#build-source">https://eisop.github.io/cf/manual/#build-source</a>.
After that succeeds, import the projects into your IDE as Gradle projects.
</p>
<p>
If your IDE cannot find <code>com.sun.source.*</code> packages, try changing the project JDK to JDK 11 or JDK 17.
</p>
<p>
For VS Code and Eclipse, run <code>./gradlew eclipseClasspath</code> before running
the IDE for the first time.
This ensures generated files are not put in the standard <code>../bin/</code> directories.
</p>
<h2 id="pull-requests">Pull requests</h2>
<p>
Each pull request should address a single concern, rather than (say)
addressing multiple concerns such as fixing a bug, adding a feature, <em>and</em>
changing formatting. Focusing each pull request on a single concern makes
the commit easier to understand and review. It also makes the commit
history (after the pull request is merged) easier to understand and (if
necessary) revert.
</p>
<p>
The pull request title should clearly explain the change. It will be used
as the commit message for your change. If the pull request fixes an issue
in the issue tracker, its title should end with "; fixes #NNN" where NNN is
the fixed issue.
</p>
<p>
Your pull request (whether it is a bug fix or a new feature) should
include tests that fail before your change and pass afterward.
</p>
<p>
If you make a user-visible change, update the manual (or add a new section)
and add a brief description at the top of the changelog
(file <code>docs/CHANGELOG.md</code>).
</p>
<p>
To reduce iterations of code review, please follow
the <a href="#code-style">coding conventions</a>.
Also enable <a href="#ci">continuous integration</a> on your fork of the Checker
Framework and ensure that it passes before you open a pull request.
</p>
<p>
A pull request marked as "draft" means it should not be reviewed. To use a
"draft" pull request for discussions, make it in a fork. If it were in
the <code>eisop</code> GitHub organization, it would use CI resources
and thus slow down CI feedback for other pull requests.
</p>
<p>
Also
see <a href="https://homes.cs.washington.edu/~mernst/advice/github-pull-request.html">Michael
Ernst's advice about creating GitHub pull requests</a>.
</p>
<h3 id="pull-requests-branches">Branches</h3>
<p>
It is good style to create a branch (in your fork of the Checker
Framework GitHub repository) for each independent change.
Do not make changes to your <code>master</code> branch.
If you have write access to the <code>eisop</code> repository, don't
work in a branch of it, because such a branch competes for CI resources
with all pull requests.
</p>
<p>
You may need to make changes to multiple repositories.
See <a href="#Related_repositories">"Related repositories"</a> above.
</p>
<p id="azure-pipelines-bug-same-commit-hash">
Azure Pipelines has a bug: whenever two CI jobs would run code with the same
commit hash, it re-uses a previous execution result. This is a bug because the
CI job's behavior may depend on the branch name and other factors that are
independent of the commit hash. This means that you may see spurious successes
or failures when your branch of (say) the <code>jdk</code> repository has the
identical commit hash to some other branch that Azure Pipelines previous ran a
job for.
</p>
<h3 id="pull-requests-maintainers">Pull request and commit notes for maintainers</h3>
<p>
It is acceptable to commit small, noncontroversial changes directly to
master. (This policy differs from some projects, which require an issue
tracker issue and a pull request for every change, however minor.)
As with pull requests, each commit should address a single concern.
For any change where you want feedback, or where others might have
useful comments or might disagree, please submit a pull request. Be
conservative in your judgment; others might consider something
controversial that you do not.
</p>
<p>
Try to review pull requests promptly, to avoid stalling others while
waiting for your feedback. If you have been waiting for more than a week
after the pull request was assigned with no feedback, then ping the
assignee, wait at least another business day, and then go ahead and push
your changes. It's great if reviewers can give feedback, but if they are
too busy to do so, you should recognize that and move on.
</p>
<h2 id="github-configuration">GitHub configuration</h2>
<p>
When you installed Git, you should have set your name and email address. If you have not yet done so, do it now:
</p>
<pre>
git config --global user.name "<em>FIRST_NAME LAST_NAME</em>"
git config --global user.email "<em>USERNAME</em>@<em>SOMEDOMAIN.COM</em>"
</pre>
<p>
Before you make any commits (even to your own fork),
update your GitHub account profile so it contains your complete name.
This is necessary to include you in
the <a href="https://eisop.github.io/cf/manual/#credits">list of
contributors</a>.
</p>
<p>
You will want your own GitHub fork of any project you plan to modify. We
recommend that, for each fork, you configure GitHub
to <a href="https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-the-automatic-deletion-of-branches">delete
branches after they are merged</a>.
</p>
<h2 id="ci">Continuous Integration</h2>
<p>
The Checker Framework has continuous integration jobs that run in GitHub Actions, Azure
Pipelines, CircleCI, and/or Travis CI on each push to GitHub.
We recommend GitHub Actions.
</p>
<h3 id="ci-github-actions">GitHub Actions</h3>
<p>
To enable GitHub Actions for your fork:
</p>
<ul>
<li>Navigate to your fork on GitHub</li>
<li>Click the "Actions" tab</li>
<li>A dialog should appear about workflows not being enabled by default on your fork</li>
<li>Click "I understand my workflows, go ahead and enable them"</li>
</ul>
<p>
To view job results:
</p>
<ul>
<li>Click the "Actions" tab</li>
<li>View the status of your workflows and click on a run to see more details</li>
</ul>
<p>
For details on what jobs are run and the commands executed, see
<a href="https://github.com/eisop/checker-framework/blob/master/.github/workflows/ci.yml"><code>.github/workflows/ci.yml</code></a>.
</p>
<h3 id="ci-azure-pipelines">Azure Pipelines</h3>
<p>
To enable Azure Pipelines continuous integration for your fork:
(This is a summary of the <a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/create-first-pipeline?view=azure-devops">Azure
Pipelines getting started directions</a>.)
</p>
<ul>
<li>Browse to <a href="https://dev.azure.com/">dev.azure.com</a>.
(You might need to create a (free) account.)</li>
<li>Click "Create a project to get started" and enter an appropriate name</li>
<li>Click "public".
<ul>
<li>If this option is not available, create the project and <a href="#project-visibility">modify its visibility</a> later.</li>
</ul>
</li>
<li>(You might have to wait a few days for your project to be created.)
<li>Click "create project"</li>
<li>At the left, click the blue rocket labeled "pipelines"</li>
<li>Click "new pipeline"</li>
<li>Click "GitHub"
(You might need to authorize the app on GitHub.)</li>
<li>Click "Select a repository"</li>
<li>Choose <em>MYUSERID</em>/checker-framework</li>
<li>Choose the default radio button, "only selected repositories". <b>Do not</b> choose "all repositories".</li>
<li>Choose "Existing Azure Pipelines YAML file"</li>
<li>Select "/azure-pipelines.yml" in the dropdown menu</li>
<li>Approve and install.</li>
<li>Click "run".</li>
</ul>
<h4 id="ci-increasing-quota">Increasing quota</h4>
<p>
By default, your project has no parallelism and thus pipeline runs fail
immediately. Azure DevOps provides
a <a href="https://aka.ms/azpipelines-parallelism-request">Microsoft Forms</a>
through which you can request increased public project concurrency for validated
open-source projects.
</p>
<p>
It may be the case that you obtain only 1800 minutes per month, only one
parallel job at a time, and only for private projects. In this case, you need
to ask Azure to lift all three restrictions. Send mail such as the following:
</p>
<p>
Thank you for granting me free tier access to Azure Pipelines.
I am working on the open-source <a href="https://github.com/eisop/checker-framework">EISOP Checker Framework</a>.
Therefore could you please make the following changes, per the policies at https://azure.microsoft.com/en-us/products/devops/pipelines/?
</p>
<ul>
<li>Increase parallelism beyond 1 job.</li>
<li>Increase time limit beyond 1800 minutes per month.</li>
<li>Permit the project to be public, for collaboration.</li>
</ul>
<p>
Thanks for your help.
</p>
<h4 id="project-visibility">How to change project visibility settings</h4>
<p>
To change your project's visibility settings (usually to "Public" to enable CI):
</p>
<ul>
<li>Browse to your project on <a href="https://dev.azure.com">dev.azure.com</a>.</li>
<li>Click the "Project Settings" button.</li>
<li>Click the "Visibility" dropdown.</li>
<li>Click "Public".</li>
</ul>
<h3 id="ci-travis">Travis CI</h3>
<p>
To enable Travis CI continuous integration for your fork:
</p>
<ul>
<li>Browse to <a href="https://www.travis-ci.com/">travis-ci.com</a></li>
<li>Click the downarrow for the dropdown, near your face in the upper right corner</li>
<li>Click settings</li>
<li>Find "checker-framework" in the list, and click the slider to enable it.</li>
</ul>
<h3 id="ci-failure">Reproducing Continuous Integration build failures</h3>
<p>
If a CI job fails, examine the CI logs.
</p>
<p>
You can also run the same test locally. Each CI job runs a different command.
You can see the commands in
file <a href="https://github.com/eisop/checker-framework/blob/master/.github/workflows/ci.yml"><code>ci.yml</code></a>,
usually on lines starting with <code>bash:</code>. The scripts that are run
generally just invoke gradle to run particular tasks.
</p>
<p>
Sometimes, CI tests for your pull request may fail even though the same command
passed locally. First, ensure you are using the same JDK. Second, all CI tests
are run in a Docker container, and you can use that container if necessary. The
container names are in top-level
file <a href="https://github.com/eisop/checker-framework/blob/master/.github/workflows/ci.yml"><code>ci.yml</code></a>,
on lines starting with <code>container:</code>.
</p>
<h2 id="Documenting_refactoring_ideas">Documenting refactoring ideas</h2>
<p>
Don't open issues for code improvement ideas (such as potential refactorings).
If it can be described concisely and is unlikely to be rediscovered by other
people, write a TODO comment in the code. The code comment is more likely to be
noticed by someone
working with the code, and it is equally easy to search for. Furthermore,
it doesn't clutter the issue tracker. Clutter in the issue tracker reduces
morale, makes it harder to search, and makes the project appear
lower-quality than it actually is.
</p>
<h2 id="annotated-library-version-numbers">Version numbers for annotated libraries</h2>
<p>
We maintain annotated versions of some third-party libraries. The source
code appears in a fork in
the <a href="https://github.com/eisop">GitHub <code>eisop</code>
organization</a>. Binaries are hosted
at <a href="https://search.maven.org/search?q=annotatedlib">Maven Central
in the <code>org.checkerframework.annotatedlib</code> group</a>.
</p>
<p>
Annotated libraries should be based on a released version of the upstream
library, not an arbitrary commit in the upstream library's version control
system. The library's version number is the same as the upstream version
number.
</p>
<p>
When making a new version of an annotated library, between upstream
releases, add ".0.1" to the end of the version number. For example, if we
already uploaded version 6.2 to Maven Central, the next version we upload
would be 6.2.0.1. This accommodates the possibility that the upstream
maintainers release 6.2.1. Our further releases increment the last number,
for example to 6.2.0.2.
</p>
<h2 id="Making_a_Checker_Framework_release">Making a Checker Framework release</h2>
<p>
See a separate document about the Checker Framework release process:
<a href="https://htmlpreview.github.io/?https://github.com/eisop/checker-framework/master/docs/developer/release/README-release-process.html">web version (from previous release)</a> or
<!-- This relative URL works from a clone, but not from the web. -->
<a href="release/README-release-process.html">local version (link works from a clone)</a>.
</p>
<h2 id="Supporting_a_new_version_of_Java">Supporting a new version of Java</h2>
<p>
To upgrade the Checker Framework to use a newer version of Java:
</p>
<pre>
# Create a branch named "java-23".
cd $t/checker-framework-fork-mernst-branch-master
gnb java-23
cd $t/checker-framework-fork-mernst-branch-java-23
# Edit:
checker/bin/wpi.sh
checker/bin/wpi-many.sh (diff it against wpi.sh)
# Rename and edit:
checker/bin-devel/Dockerfile-ubuntu-jdkXX
checker/bin-devel/Dockerfile-ubuntu-jdkXX-plus (diff it against Dockerfile-ubuntu-jdkXX)
# Further search for: (java|jdk).?23\b
# Don't push changes yet.
# Use the latest version of Gradle, which supports the new JDK version
# (see https://docs.gradle.org/current/userguide/compatibility.html):
for wmtest in wpi-many-tests-bcel-util wpi-many-tests-bibtex-clean wpi-many-tests-ensures-called-methods wpi-many-tests-html-pretty-print wpi-many-tests-owning-field -wpi-many-tests-bibtex-clean ; do
cd $t/$wmtest && \
(./gradlew wrapper --gradle-version 8.10 && ./gradlew build --warning-mode=all) && \
git commit -m "Use Gradle 8.10" gradle/wrapper/gradle-wrapper.properties && \
git push
done
# Now update file checker/tests/wpi-many/testin.txt.
# Build the Docker images for the newest JDK version (others need not be rebuilt).
# Push changes. Fix any build failures.
</pre>
<h2 id="Case_studies">Describing a case study</h2>
<p>
After you have performed a case study of applying some checker to an
open-source codebase, you should have:
</p>
<ul>
<li>
the unannotated code, as of the time/commit you started annotating it.
This might be in your forked repository, or in an upstream repository.
</li>
<li>
the annotated code. Typically, this is in a branch of your forked repository.
<p>
In the annotated code, each <code>@SuppressWarnings</code> annotation should have a brief justification, explaining why the code is correct and the warning is a false positive.
The justification should be a <code>//</code>-style comment, on the same line as the argument to <code>@SuppressWarnings</code>. For example:
</p>
<pre>
@SuppressWarnings("nullness:assignment") // dynamic check: checked against null immediately above
@SuppressWarnings({
"nullness:assignment" // dynamic check: checked against null immediately above
})
</pre>
If there are more than about 10 warning suppressions, prefix each one by a
category followed by a colon (as with "dynamic check:") above, to aid in
computing statistics about the causes of false positive warnings.
</li>
<li>
the command to run the type-checker(s) on the annotated code.
</li>
<li>
a list of all the bugs you fixed, with a brief description of each. The
description can point to pull requests, or commits, or just be text; provide
whatever is most helpful.
</li>
</ul>
<h2 id="Counting_annotations">Counting annotations</h2>
<p>
After you have annotated a project, you may wish to count the annotations that you have written.
These programs will help you do that:
</p>
<ul>
<li><a href="https://eisop.github.io/cf/api/org/checkerframework/common/util/count/AnnotationStatistics.html">AnnotationStatistics</a></li>
<li><a href="https://eisop.github.io/cf/api/org/checkerframework/common/util/count/JavaCodeStatistics.html">JavaCodeStatistics</a></li>
<li><a href="https://eisop.github.io/cf/api/org/checkerframework/common/util/report/ReportChecker.html">ReportChecker</a></li>
<li><a href="https://github.com/eisop/checker-framework/blob/master/checker/bin-devel/count-suppression-reasons">count-suppression-reasons"></a></li>
</ul>
<h2 id="Build_historical">Building a historical version of the Checker Framework</h2>
<p>
The use of four different repositories, as explained in
"<a href="#Related_repositories">Related repositories</a>" above, means that you
cannot just check out an old version of the Checker Framework and build it
with <code>./gradlew assemble</code>. By default, the Checker Framework build
uses the latest version of the other three repositories, which are rarely
compatible with an old version of the Checker Framework. One symptom of the
problem is a "Can't find stubparser jar" error message.
</p>
<p>
To build an old version of the Checker Framework, you need to use old versions
of the other repositories as well. Clone them into siblings of
the <code>checker-framework/</code> directory that holds your old version of the
Checker Framework.
</p>
<p>
Here are <b>general rules</b>:
If the Checker Framework version is a commit on branch B with date D, then use
the commits on other repositories' branch B (or <code>master</code>, if branch B
does not exist) that precede D. (This isn't quite right, because the commits
may have been made earlier but all pushed at the same time, so you might need to
look at commits that are relatively soon after D.) To obtain these, view the
GitHub history and click on the pull request to see the commits that were merged
into it. You cannot obtain these from the Git history, because after a pull
request is merged, the commits in the pull request branch are squashed and the
branch is deleted.
</p>
<p>
Here are <b>special cases</b>:
</p>
<ul>
<li>
If you are building an old <em>released</em> version of the Checker Framework,
then <code>annotation-tools</code> should have a corresponding tag for the
release.
</li>
<li>
Recently, any Stubparser change that breaks building the Checker
Framework, should have a new version number. So you should check out
Stubparser to the commit that changed the version number (to what it is
in <code>checker-framework/build.gradle</code>).
</li>
</ul>
<p>
The script <code>checker/bin-devel/checkout-historical.sh</code> approximates
these rules. It is able to build the Checker Framework back through at least
mid-April 2019. It cannot build the Checker Framework as of mid-January 2019.
</p>
</body>
</html>
<!-- LocalWords: TODO javacutil gradle javadoc reformats subprojects pre NullAway CircleCI travis ci downarrow dropdown MYUSERID NNN doesn AnnotationStatistics JavaCodeStatistics stubparser wpi Dockerfile ubuntu jdkXX jdk wmtest bcel util bibtex html cd ReportChecker pids mernst gnb
-->
<!-- LocalWords: subproject personalblog changelog config SOMEDOMAIN YAML isn
-->