Prolint is a tool for automated source code review of Progress 4GL code. It reads one or more sourcefiles and examines it for bad programming practice
When you are interested Prolint, you are encouraged to subscribe to this group where you find the on-line tools to collaborate and discuss Prolint. There is a discussion forum, you can submit issues (for bugs and enhancement requests), you can modify the on-line documentation, and best of all: there is an e-mail list. So subscribe, and then don't forget to go to your subscription details to enable the e-mail notification!
Prolint is a tool for automated source code review of Progress 4GL code. It reads one or more sourcefiles and examines it
for bad programming practices or violations against coding standards.
Prolint does not change or rewrite source code, it is no beauty.p.
Prolint works with a customizable library of "rules".
A "rule" is a specific test that Prolint can perform on source code. Some examples:
These are just some examples, the complete current list on page "Prolint rules".
Every rule has a 'severity-level' ranging from 0 to 9 (0=informational, 9=severe violation).
You can easily customize the severity levels to your company preferences.
You can also switch rules on/off and save these settings in any number of "profiles".
A "profile" is a set of custom preferences.
Prolint is designed to make it easy to add or remove customized rules (one of the objectives of the Open Source Project is to improve the library of rules).
The output of Prolint contains the following fields:
The output goes to a delimited text-file or to a result window.
A delimited text-file is convenient when Prolint works on a large amount of sourcefiles in batchmode.
The text-file is formatted in a way that makes integration with IDE's possible. For example, the file can be
formatted like a search-results file for the ED4WIN programmer's editor.
The result window is a Progress 4GL window with a browse widget.
The browse widget shows Prolint output in a temp-table.
The result window is convenient when Prolint works on a single sourcefile or a small set of
sourcefiles from within the Progress ADE.
A Help-button shows help about the rule on the current browse line.
Prolint can be invoked in a number of ways:
Customizations or user-preferences are set in a stand-alone program with a GUI interface.
This program can be added to the PRO*TOOLS menu.
Prolint is a set of Progress 4GL procedures, not using any smart-objects.
The core of all parsing is performed by a DLL: proparse.dll.
Proparse.dll reads Progress 4GL source code and represents the tokens as nodes in a treeview in memory, which can be accessed from the 4GL (much like the DOM in an XML parser).
Prolint is an Open Source project.
Proparse is also an Open Source project. You can download the compiled library from http://www.joanju.com
The following release files are zipped executables of a setup-program. The setup program is a Windows executable, but Prolint itself can run on any platform.
Only the latest release is available from this page, if there is a demand for previous releases just let me know and I will add it.
Prolint is distributed under the terms of the LPGL license.
If you want to know what has changed, read the revision history.
If this is your first time download, please read the installation instructions.
The latest release of Prolint is release 72 (12 April 2008)
Download this when you are using Progress version 9 or up.
Download Prolint 72: click here
When you are using Progress version 8, then Prolint release 63 is for you. The later releases of Prolint won't run in Progress 8.
Download Prolint 63: click here
You can browse releases (including the latest release) and fetch a tarball using the WebSVN interface here:
websvn.oehive.org Prolint Tags
The pages in this chapter will guide you through the installation of Prolint.
Prolint is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
Prolint is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
A copy of the GNU Lesser General Public License is
available online in file lpgl.txt and also available as file "license.txt" in the Prolint directory.
More information about this and other GNU licenses can be found at the GNU website.
Prolint is based on the latest version of Proparse.
Before you can run Prolint you will need to install Proparse from www.joanju.com.
Proparse is available for Windows, Linux and several Unixes.
Installation on Windows:
Follow the installation instructions for Proparse, which basically just tells you to install to directory "proparse" under a directory that is already in your PROPATH.
In other words, assuming that c:\p4gl\tools is an existing directory in your PROPATH you will eventually end up with:
c:\p4gl\tools (existing directory, already in your PROPATH) c:\p4gl\tools\proparse (contains proparse.dll and sources)
This way you will not have to change your PROPATH to run Proparse.
Prolint must be a subdirectory of one of the directories in your PROPATH. I suggest you install Prolint parallel to Proparse. If, for example, you already have an existing directory c:\p4gl\tools in your PROPATH you would end up with:
c:\p4gl\tools (existing directory, already in your PROPATH)
c:\p4gl\tools\proparse (contains proparse.dll and sources)
c:\p4gl\tools\prolint (contains prolint sources)
This way you will not have to change your PROPATH to run Prolint or Proparse.
If you have downloaded the setup program for Windows (prolint_nn.exe) simply specify the name of the basedir (in this example: "c:\p4gl\tools").
The setup program does not overwrite any existing files in prolint\settings, so your custom settings are preserved.
It has the built-in safety to abort entirely when you are trying to install an old Prolint release over a newer release: the setup program looks at help/release.ini to see which release is currently installed.
If you have downloaded the zip-file (prolint_nn.zip) it's all up to you to make sure that you are not overwriting anything that you would like to keep.
Unless you are running Progress version 8 or TTY mode, you will need to extract adecomm.pl.
This is because the codepreview window contains an editor, which uses the same syntax-coloring editor as the Progress Appbuilder, and adecomm.pl contains the includefiles that makes this possible.
Open a command shell and change directory to your DLC directory. In the following example I will assume this is directory "c:\Program Files\Progress" :
cd \progra~1\progress\gui |
When you have installed proparse and prolint you are ready to run Prolint for the first time.
Let's take the quick tour:
run the following statement from a Progress procedure editor:
RUN prolint/desktop.w.
In the Prolint Desktop, choose button "Lint files...".
You will now see a dialog, titled "Prolint - select files to lint".
This dialog contains an editor widget where you can enter a list of sourcefiles that will be processed by Prolint. Each filename should be entered on a new line, wildcards are currently not supported.
The easiest way to populate the list is by using drag and drop: open a Windows Explorer, select one or more
Progress sourcefiles and drag/drop them into the dialog.
Please note that Prolint can only do its work on sources that are syntactically correct: the Progress compiler must be able to compile them without errors.
That's why we actually prefer the term "compilation unit" instead of "sourcefile": an includefile is a sourcefile but not a compilation unit.
For this first test, just select one or two files and press the OK button.
After you pressed OK, the dialog will immediately disappear and now you will see the "Prolint Results window" unless you are using a TTY-client.
Proparse will now initialize itself and show its splash screen (the frog picture). This may take a little while because proparse needs to read the database schema, but this only happens the very first time
in each Progress session. When you run prolint again (in the same Progress session) initialization will be skipped.
When initialization is done, Prolint will start inspecting the compilation-units you selected. After that you will get to
see a list of warnings in the Results window, unless Prolint didn't find anything in your source to warn about (in that rather unlikely case, the
status bar of the Results window will indicate "0 warnings").
When you double-click on a warning, an external text editor will open the sourcefile to the specified line number
(actually, this feature will probably not work for you yet, because it is by default configured to launch UltraEdit-32. We will change that later in "settings").
You can now press button "Lint current" - this will run prolint again for the compilation-unit on the currently selected browse row.
Or you can press button "Lint files" which will start the first dialog again, where you can select a new set of files to lint. Or you can open a popup-menu
on the browse (right-mouse button) and open a help file explaining the rule for the focussed line.
Visit the Prolint discussion forum
(but if you have an idea for a new rule, please use the Issue Tracker and use the combo-boxes to specify "component=rule" and "category=feature request")
When you are not subsrcribed to the Prolint group, you will not be able to post anything in the Forum.
Subscribing only takes a second or less, and you can unsibscribe whenever you want.
When you are subscribed, you can also opt to receive e-mail notifications for any group activity (like new Forum posts or other events in the Prolint group). This is however an optional step, that you can enable in menu option "my subscription".
Prolint reads your source code and looks for bugs and does suggestions for improvements. This Prolint project works in conjuction with the Prolint group
If you have an idea for a new rule, please use the Issue Tracker and use the combo-boxes to specify "component=rule" and "category=feature request".
But of course you can use the Issue Tracker for other issues too.
Important: if you are upgrading to Prolint 71 and use Roundtable integration, you MUST change rtb_evnts.p to avoid errors. The change only takes a minute and is described at page Repair your Roundtable Integration
New in this release is support for Roundtable 10.1b, created by Thomas Hansen.
The old directory "prolint/rtb" is gone and replaced by a new directory "prolint/roundtable/" + version-number.
Also new are a bunch of rules created by Glen West:
The optional Prolint database (prolintdb) has undergone many changes. When you were not using prolintdb then it won't be an issue for you, but if you are already using prolintdb then you will have to upgrade its schema, either by creating a new prolintdb database or by importing de delta-df in file "prolint/prolintdb/prolintdb-v1-delta.df".
More OOABL syntax recognition and one new rule. To use Prolint with OO classes you must have Proparse 3.1a.
Bugfix release and also one new rule:
Several changes to make Prolint work with OOABL classes (but don't worry Prolint still works in DLC 9 too):
Several other enhancements, not related to OOABL:
Important: Prolint 64 does not run in Progress version 8 anymore.
If you are still running Progress 8, then please use Prolint release 63.
No new features but performance improvements. The overall performance improvement in my test was around 10%, but depends highly on the files you inspect, which rules you choose and how many warnings are generated.
The Results window (logwin) is completely rewritten by Ildefonzo. It now contains
a treeview and a listview, and a very convenient code preview pane too.
This new Results window is the default if you are using Progress 9.
If you are using Progress 8, you will automatically get the old
Results window which has been renamed to logwin8.
Features of the new Results window:
Prolint.p and Lintsuper.p have been changed to support obsoletenodes:
New rules to help you test if your source is ready to be used with an Oracle dataserver:
New rules and improvements by Breck Fairley and Jamie Ballarin:
Also:
The main purpose of this, is to copy warnings from the Results window to
the "Build"-window in ED for Windows (the editor), using the current filter and sort order.
This is by far the easiest way to correct your sourcefiles!
You will also need to download todays version of proed4w to do this.
See integration with ED for Windows for details.
IF ready THEN
ASSIGN
x = a
y = b.
z = c.
END PROCEDURE. /* end of procedure AA */ PROCEDURE BB :
No functional differences, added conditions for the GNU Lesser General Public License.
Bugfix: profile "<none>" failed.
New: the option to use "local profiles". The existing profiles in directory "prolint/settings" are from now on "shared profiles".
Local profiles can be convenient when:
The lists of Local profiles and shared profiles are merged at run-time, local profiles take precendence unless the shared profile is marked as "not overrideable".
See page "profiles" for more info.
Some minor changes for compatibility with Proparse 1.0f00.
Proparse 1.0f00 (or later) is required for this release of Prolint, see
http://www.joanju.com
Other than that, there are no changes in Prolint at this
moment.
Wouldn't it be great if "ED for Windows" had a toolbar-button to run Prolint for the source you're editing? Well, read on..
Gerry Winning has improved the integration with
Roundtable:
Note: you have to include {prolint/rtb/custom_evnt.i} in
roundtable/rtb_evnt.p and recompile it before these
changes are effective. The old {prolint/rtb/addmenu.i}
is now obsolete because it's name is not descriptive
anymore and can be removed.
Thanks Gerry!
This version requires Proparse 1.0e01.
Internal changes to Prolint by John Green for
compatibility with Proparse 1.0e01:
Prolint is tested with Proparse 1.0d.
Other than that, there are no changed in Prolint at this
moment.
This release of Prolint only has some internal changes to take advantage of new functions in Proparse 1.0c.
There are no functional differences but Prolint will probably run faster now.
Prolint will not run with Proparse 1.0b or older.
Prolint does not use any of the following functions anymore: ParserGetTopNode, ParserGetFirstChild, ParserGetNextSibling.
If you are using OpenEdge and Object Oriented ABL, then you definitely need to update Prolint to release 66. Until now Prolint did not know what a class or a method was, and would give all kinds of silly warnings.
If you are using Progress 9, you may also want to upgrade to Prolint 66 to take advantage of new rules that check if you didn't forget DEFINE BUFFER statements in the scope of internal procedures and user-defined functions. (and yes, in methods too of course). There was a long and lively discussion on PEG about this recently.
As always, you can download Prolint from page http://oehive.org/prolint/download and read the revision log here: http://oehive.org/prolint/history.htm.
If you want, you can also dive into the Subversion logfiles directly: tags/release 66 or monitor the trunk with your RSS reader.
Prolint 70 is now available! Note: It requires ProParse 3.1a released in April 2007.
This release is all about the Prolint database. It provides a session identifier with any lint session, like Progress Profiler’s Profiler ID, so that you can compare sessions over time. This allows you to see the improvement (or the opposite) over time as people work on the code.
If you are not using the profiler database now, the prolint\prolintdb\prolintdb.df will get you the current database structure. If you are, you can apply the prolint\prolintdb\prolint-v1-delta.df to get the new table and column. In order to make use of the new session-based statistics, you must use the new version of the prolint database.
The major changes are:
1) In Select Files to Lint, there are 3 new buttons. These new buttons are only visible if the new database is connected with the new table, and one of the output handlers includes the database. If you want to start a new session to start gathering statistics, select New Session. If you want to add warnings/statistics to an existing session, select Find Session. If you want to place all your results in the “Zero” session for broader statistical analysis (a baseline), then select No Session.
2) The desktop, and the results window, now provide a button to get session comparison statistics. This is useful to compare two sessions against each other – usually for programs they have in common. Full documentation on this window can be found at http://www.oehive.org/node/945.
3) The results window now has the ability to load the results of a previous session out of the prolint database by use of the Load Results button (full documentation on this window can be found at http://www.oehive.org/node/944). Here you select a session and click Load, and all the results of that session are reloaded into your results viewer window where you can do filtering and analysis. In addition, it provides a link to the statistical analysis by session described in 2 above.
4) The existing statistical analysis programs accessible from the Desktop window, for subdirectory, include file, and rule, still function. They operate only on session 0, so to get the base data you need to run the lint process on all desired code with session 0 (or No Session) selected. The rest remains unchanged.
I hope that the community finds these new features as helpful as we will.
Glen West
Only one week after release 66, so this must be a bugfix release...
Prolint learned some more about OOABL syntax. A new rule was added (publicvar) to search for PUBLIC VARIABLE statements in class files, because they have to be replaced by PROPERTIES in my humble opinion.
Not everything in release 66/67 is about OOABL.
The new rules bufdbproc, bufdbfunc and bufdbmeth are effective in "oldfashioned" procedural ABL too. But last week I made a silly bug in those rules and fixed it.
To get your free copy..... go to the download page!
Prolint 69 is ready!
It requires Proparse 3.1a that was released by John two days ago.
This release of Prolint could be aliased as "the OOABL release", because it can analyze every Object Oriented syntax construction. When it analyzes a class, it even looks in inherited classes to take inherited properties and non-private variables from those ancestors into the equation. Try that with grep :-)
But of course Prolint can still run in Progress 9 and analyze "traditional" procedural code as well.
In fact there are some new rules that are usefull for procedural source:
- nestedfunc: it may be a matter of taste but I don't like it when functions are defined inside code blocks. This rule agrees with me.
- incslash and inclowercase: test if the filename in an include directive {dir/file.i} looks like Unix compatible, eg no uppercase and no backslashes
So regardless if you are writing classes or not, upgrade to Prolint soixante-neuf from the download page.
And don't forget to upgrade to Proparse 3.1a first.
At last! This release is way overdue because it contains rules that were submitted by Glen West months ago.
Big news: Prolint integrates with Roundtable 10.1b !! Thomas Hansen adapted the existing integration for Roundtable 9.1a-c and now it works for Roundtable 10.1b.
A little bit unfortunate for existing users, who upgrade to Prolint 71 and were already using the Roundtable integration, is that they need to update their "rtb_evnts.p" procedure. It is simple: just follow the instructions on page Repair your Roundtable Integration.
Download your latest Prolint from http://www.oehive.org/prolint/download
Enjoy!
The source code for Prolint is managed in a Subversion repository, here at the OpenEdge Hive.
You can also find a Subversion repository at Sourceforge.net, but that one is outdated.
View the repository in your web browser:
http://websvn.oehive.org/listing.php?repname=prolint
or if you prefer to use a subversion client (like svn.exe or TortoiseSvn) then you can export the trunk from svn://oehive.org/prolint/trunk/prolint
This chapter will explain the various configuration options for Prolint
# this file specifies which particular warnings should be excluded. The rules will
# still be executed, but warnings are intercepted if they match this file.
# You can also consider using {&_proparse_ prolint-nowarn(ruleid,ruleid)} directives
#
# format:
# sourcefile|rules
#
# sourcefile : spell exactly as it appears in "Prolint result window",
# wildcards are accepted. CAN-DO rules apply
# rule : comma separated list of identifiers of the rules that gives the warning,
# wildcards are accepted. CAN-DO rules apply
#
# empty lines or lines matching #* are ignored
# exclude everything from directories adm and adm2:
adm/*.i|*
adm2/*.i|*
# from file ifindent.i, allow rules ifindent1 and ifindent2 but exclude all other rules:
prolint/regrtest/ifindent.i|!ifindent*,*
# this file specifies which particular warnings should be suppressed. The rules will
# still be executed, but warnings are intercepted if they match this file.
# You can also consider using {&_proparse_ prolint-nowarn(ruleid,ruleid)} directives
#
# format:
# sourcefile|rule|linenumbers
# sourcefile|_file-size|size
#
# sourcefile : spell exactly as it appears in "Prolint result window"
# rule : identifier of the rule that gives the warning
# linenumbers: comma separated list of linenumbers where the warning would occur when not suppressed
#
# size : the filesize of the sourcefile, in bytes
# if _file-size is not specified, or if size doesn't match the actual size of the sourcefile,
# all lines for sourcefile will be invalid. So after you edit a sourcefile no warnings will be suppressed.
#
# empty lines or lines matching #* are ignored
# unfortunately when you lint prolint itself you will get a lot of warnings from proparse.i
proparse/api/proparse.i|_file-size|3179
proparse/api/proparse.i|varusage|8,10,12,14,16,18,28,30,34,36,38,40,42,44,48,50,62,64,67,70,72,74,76,78,80,84
proparse/api/proparse.i|nocomment|8
proparse/api/proparse.i|nocomment|10
proparse/api/proparse.i|nocomment|12
proparse/api/proparse.i|nocomment|14
proparse/api/proparse.i|nocomment|16
proparse/api/proparse.i|nocomment|18
proparse/api/proparse.i|nocomment|20
proparse/api/proparse.i|nocomment|22
proparse/api/proparse.i|nocomment|24
proparse/api/proparse.i|nocomment|26
proparse/api/proparse.i|nocomment|28
proparse/api/proparse.i|nocomment|30
proparse/api/proparse.i|nocomment|32
proparse/api/proparse.i|nocomment|34
proparse/api/proparse.i|nocomment|36
proparse/api/proparse.i|nocomment|38
proparse/api/proparse.i|nocomment|40
proparse/api/proparse.i|nocomment|42
proparse/api/proparse.i|nocomment|44
proparse/api/proparse.i|nocomment|46
proparse/api/proparse.i|nocomment|48
proparse/api/proparse.i|nocomment|50
proparse/api/proparse.i|nocomment|52
proparse/api/proparse.i|nocomment|54
proparse/api/proparse.i|nocomment|56
proparse/api/proparse.i|nocomment|58
proparse/api/proparse.i|nocomment|60
proparse/api/proparse.i|nocomment|62
proparse/api/proparse.i|nocomment|64
proparse/api/proparse.i|nocomment|66
proparse/api/proparse.i|nocomment|68
proparse/api/proparse.i|nocomment|69
proparse/api/proparse.i|nocomment|70
proparse/api/proparse.i|nocomment|72
proparse/api/proparse.i|nocomment|74
proparse/api/proparse.i|nocomment|76
proparse/api/proparse.i|nocomment|78
proparse/api/proparse.i|nocomment|80
proparse/api/proparse.i|nocomment|82
proparse/api/proparse.i|nocomment|84
Prolintdb consists of an outputhandler to write warnings to a database, and a couple of programs to help you query the database.
the user story:
Suppose you have a pretty large software project and want to inspect it with Prolint. It will take a long while for Prolint to finish the job,
so you would like to run Prolint unattended and look at the warnings later. Since it is a large software project Prolint will probably find
thousands of warnings, so you need tools to help you generate an overview.
Make sure the prolintdb database is connected with logical database name "prolintdb".
Run Prolint as usual, but select a profile that uses outputhandler "prolintdb.p". This outputhandler is responsible for writing warnings to the database.
When you do not want to write anything to the database, then just don't use outputhandler "prolintdb.p".
To query warnings that are stored in the prolint database, you can use the windows "Statistics by rule" and "Statistics by subdirectory".
These windows can be launched from the Prolint Desktop window.
These windows don't actually query the warnings that are generated by the outputhandler, but they query statistics.
These statistics are also stored in the database but need to be calculated manually: just press
button "Recalculate" in one of the statistics windows. Statistics are not automatically refreshed after you run Prolint, you just need to press the Recalculate-button.
From the two statistics windows, you can use button "Show Results" to see the actual Prolint warnings that were saved by the outputhandler.
This button launches the usual "Prolint Results Window" and publishes the selected warnings to that window.
Once the selected warnings are visible in the Results window, you can use all the features of that window including: open the sourcefiles at the specified line number, re-lint the selected compilation unit, etc.
Please notice that the "Prolint Results window" assumes that you have been using a profile named "prolintdb".
When you want to re-lint a selected compilation unit, the Results window will try to do that with profile "prolintdb".
So it is required to actually have such a profile, and to make sure that this profile uses outputhandler "prolintdb.p".
You don't always want to run every rule. A "profile" contains a specification of the rules you want to skip and which outputhandlers you want to use. You can create as many profiles as you want.
For example, you may want to create a profile named "indexes" that only uses rules "nowhere", "sortaccess" and "wholeindex" and writes its output to HTML and to a tab-delimited file. Or you may want to ue profile "Ed4Win" that writes its output to the build-window in ED for Windows.
Each subdirectory in "prolint/settings" is a profile. Each of those subdirectories contains a couple of ascii-files to define the characteristics of the profile.
Profiles in "prolint/settings" are considered to be "shared" profiles.
In addition to "prolint/settings" you can also create a directory "local-prolint/settings" anywhere in your propath. Each subdirectory in "local-prolint/settings" is also a profile, and these are considered to be "local" profiles.
you can achieve two different goals with local profiles:
The list of profiles, available in a prolint-session, is merged from profiles in both "prolint/settings" and "local-prolint/settings".
A local profile overrides the shared profile, unless the shared profile contains a file named "no-local-settings.lk". The contents of this file is not important, but the existence of such a file notifies prolint that only the shared profile should be used and the local profile will be ignored.
for a GUI-window to modify the settings described here:
run prolint/core/lintcfg.w("")
See page "lintcfg" for features of this window.
specifies which rules to run and allows to customize severities.
inherits prolint/rules/rules.d
each line has two or three fields:
specifies a list of outputhandlers to start for this profile.
these are programnames found in directory prolint/outputhandlers.
Prolint 'knows' for each outputhandler if it requires a specific Progress version or GUI/ChUI mode. It will not run the
outputhandlers that don't match the current Progress session. This means you can safely select "logwin" even if you
are running a ChUI session, because in that case Prolint will simply skip "logwin".
If file handlers.d is missing, or if the file is empty, or if it only contains outputhandlers that are not supported
in the current Progress session, then Prolint will terminate with an error message.
Same purpose as putting {&_proparse_ prolint-nowarn(ruleid)} in source, but may be more convenient if the source is
maintained by someone else (like sources in adm2/src)
See example nowarn.lst for details.
for a GUI-window to modify the settings described here:
run prolint/core/lintcfg.w("")
Directory prolint/settings shows an example of how custom profiles can be used.
Each profile represents a subdirectory in prolint/settings.
Such a subdirectory may contain configuration files describing the behavior of Prolint.
The name of the custom profile is passed to Prolint as an input parameter. For example:
RUN prolint/core/prolint.p (sourcefile, ttemptablehandle, "relaxed", true).
tells prolint to look for configuration files in directory prolint/settings/relaxed.
The configuration files in this directory may tell prolint to skip all rules with severity<6, for example.
If the parameter is blank or points to a non-existing directory, prolint will
use directory prolint/settings instead because this contains the default settings.
Profiles can be attractive when prolint is called from other ADE-tools to specify the
context where prolint is called from.
For example, Roundtable might run prolint.p(.., .., "rtb check-in",..)
during its pre-validation on check-in.
The Application compiler might run prolint.p(.., .., "application compiler",..)
which might tell prolint to write results to a logfile instead of using the results window.
Note: directories are searched in PROPATH.
file exteditor.cfg specifies how a source file can be opened in an external editor, like for example Ed4Win or UltraEdit etc.
exteditor.cfg contains just two lines:
These two lines are passed to the operating system. Each of these lines may contain &1 and &2, which are substituted by
filename and linenumber respectively, using the Progress SUBSTITUTE function.
example (for UltraEdit-32) :
"C:\Program Files\UltraEdit\UEDIT32.EXE" "&1/&2"
(in this example the double quotes are used for supporting long filenames.)
If your program requires database aliases to exist before it will compile, then you must use this file to tell Prolint about your database aliases before that program can be parsed.
The file may contain several lines, each line contains two fields: aliasname and databasename. Example:
"demo" "sports2000" "archive" "sports2001"
In this example, "demo" is an alias for database "sports2000" and "archive" is an alias for database "sports2001".
See profiles
Sometimes Prolint may raise a warning you don't agree with.
For example, rule "noundo" might warn that a specific temp-table is defined without NO-UNDO while you are certain that not using no-undo
is intentional.
In such cases you may want to suppress the Prolint warning.
There are two separate ways to suppress warnings:
Finally, if you really completely disagree with a rule, you can put it in the "skiprules" list. In that case Prolint will pretend the rule does not exist at all. The "skiprules" list is file "prolint/custom/rules/skiprules.lst". Its format is simple: each line contains one rule-id.
Let's begin with an example:
{&_proparse_ prolint-nowarn(noundo)}
DEFINE TEMP-TABLE tt_mytable
FIELD code AS CHAR
FIELD desc AS CHAR INIT "<description>"
INDEX idx_code AS PRIMARY UNIQUE code.
|
When Prolint executes rule "noundo" it will simply skip the statement, the statement is invisible to the rule.
Prolint will still give a warning for rule "abbrevkwd" because INIT is an abbreviation for INITIAL, and a warning for
rule "strattrib" because "<description>" does not have any string attributes.
If you are sure you want to suppress these warnings too, you can extend the _proparse_ directive to:
{&_proparse_ prolint-nowarn(noundo,abbrevkwd,strattrib)}
DEFINE TEMP-TABLE tt_mytable
FIELD code AS CHAR
FIELD desc AS CHAR INIT "<description>"
INDEX idx_code AS PRIMARY UNIQUE code.
|
Note:
There is no way to suppress all warnings.
There is also no way to suppress warnings for a larger scope than just one single statement.
This is intentional: adding _proparse_ directives is meant to be more work than fixing the cause of the warning.
Another note:
Please don't use the _proparse_ directive immediately after the ELSE keyword.
/* this does not work and confuses the parser: */ IF False THEN RUN first.p. ELSE {&_proparse_ prolint-nowarn(runname)} RUN Second.p. /* this is better: */ IF False THEN RUN first.p. ELSE DO: {&_proparse_ prolint-nowarn(runname)} RUN Second.p. END. /* or this is also fine: */ {&_proparse_ prolint-nowarn(runname)} IF False THEN RUN first.p. ELSE RUN Second.p. |
Filters intercept warnings after they are created by a rule, but before they are published to outputhandlers. Filters can modify or hide warnings.
You can create new filters, or configure existing filters. See topic "filter plug-ins" for more information.
Turbolint is a Dynamic Link Library that contains 3GL versions for some of the rules. The purpose of Turbolint is to improve the overall performance of Prolint, by running the 3GL rules instead of the 4GL rules.
The rules contained in Turbolint are supposed to be identical to the 4GL rules, only faster.
Turbolint.dll does not contain 3GL versions of every existing 4GL rule.
By default, if a 3GL rule exists in Turbolint.dll, then Prolint will use this 3GL version instead of the 4GL version.
Obviously if a rule does not exists in Turbolint.dll then Prolint will use the 4GL version.
Turbolint.dll currently contains the following rules:
abbrevkwd,blocklabel,ifindent,ifindent1,ifindent2,noundo,nowhere,recid,runargs,sepdbui,substitute,varusage
The ultimate goal is not to have every rule in Turbolint, only the really slow ones.
Sometimes you may want to prefer the 4GL version of a rule, even if Turbolint contains a 3GL version. For example when you are modifying or debugging the rule.
There are different ways to force Prolint to use the 4GL rule:
custom rules always take precendence over standard rules. Just copy the rule from directory "prolint/rules" to "prolint/custom/rules". Because if Prolint can find a rule in "prolint/custom/rules" then it's a custom rule, and will be run instead rules with the same name in "prolint/rules" or turbolint.
If you don't want to make a custom rule, but still want to run a 4GL rule instead of a 3GL rule, then you can specify so in file
"prolint/custom/prolint.properties.p" :
For example:
RUN SetProlintProperty ("Turbolint.RulesToIgnore", "noundo,varusage").
will force Turbolint to NOT run its built-in versions of rule "noundo"
and "varusage", and Prolint will run the 4GL versions instead. See
file prolint/prolint.properties.p for more details.
Finally, you can simply remove or rename file "prolint/turbolint.dll" so Prolint cannot find it. Prolint will then simply fall back to its 4GL rules.
This book will teach you how you can customize Prolint.
How the "prolint/custom" directory is used by Prolint:
When Prolint executes a rule, it will search the rule in this order (regardless if the rule was listed in "prolint/custom/rules/rules.d" or not):
When the Prolint Results Window searches for help on a specific rule, it will first search in directory "prolint/custom/help/rules" for a HTML file and if it doesn't find it, then it will browse to The OpenEdge Hive for on-line help.
Each rule is a non-persistent procedure located in directory prolint/rules. A rule will be invoked by prolint.p if it is listed in file prolint/rules/rules.d.
An easy way to insert a new record in this file, is to run dialog
prolint/core/dnewrule.w.
This dialog can be invoked from the Prolint Desktop window.
The file contains the following fields per record:
Set as many logicals to "no" as possible, this saves performance when the end-user doesn't run many rules.
Each rule should have help.
For standard rules (rules that are deployed with Prolint) these are topics at oehive.org. Simply create a book page as child of oehive.org/prolint/rules and it will work.
For custom rules (that you keep privately) you can create a .htm file in directory "prolint/custom/help/rules", see custom help for more info.
Run prolint/launch/test.p often, to see if rules behave as expected.
See topic "regression testing" for more details.
It is often convenient to write test-cases in directory prolint/regrtest before starting to program your new rule, so you have immediate feedback while programming.
If you add test-cases please send them to me so they are included in the next Prolint release.
File "prolint/rules/_template.p is a template for a new rule. You can use it as a starting point, if you don't want to start from scratch.
Each rule needs a couple of input parameters, which are defined by {prolint/core/ruleparams.i}.
I hope these parameters don't need introduction, although parameter "pragma_number" may be a stranger:
Pragmas are used for suppressing warnings. If the sourcefile contains a directive like {&_proparse prolint-nowarn(rule_id)}, then every node in the statement following the
directive will get an attribute. The identifier of the attribute is an integer named "pragma_number", the value of the attribute is 1 (to indicate that the attribute is "set").
Each rule_id has its own unique pragma_number. The procedures for searching through proparse nodes will skip each node where this pragma-attribute is set.
When the rule finds a statement or a situation where it wants to raise a warning about, you should run procedure PublishResult.
Procedure PublishResult is implemented in prolint/core/lintsuper.p which is
a super-procedure to every rule.
You should not
"publish" the warning directly to the outputhandlers using PUBLISH "Prolint_AddResult", because if you do you miss the extra functionality that lintsuper.p adds to it.
Searching nodes in the parsed source tree.
There are basically two ways to query nodes in the tree created by proparse:
Both procedures have identical parameter signatures, so they can be exchanged at any time - just pick the fastest one. Alternatively you can run
searchNode (also in lintsuper.p) which will choose to run either searchNodeTree or searchNodeQueries for you.
Parameters for searchNode* procedures:
Prolint release 63 runs in Progress 8 and in Progress 9. Prolint release 64 (and up) does not run in Progress 8 anymore.
When you create a custom Prolint rule you may also want to provide a Help file.
When your custom rule has id "xyz" then simply drop a file "xyz.htm" in directory "prolint/custom/help/rules".
When no custom help file is found, Prolint will try to open topic "xyz" at oehive.org.
This snippet from prolint/outputhandlers/logwin.w explains why:
FILE-INFO:FILE-NAME = "prolint/custom/help/rules/":U + pContext + ".htm":U.
IF FILE-INFO:FULL-PATHNAME<>? THEN
fullpath = file-info:FULL-PATHNAME.
ELSE
fullpath = "http://oehive.org/prolint/rules/":U + pContext.
RUN prolint/core/openhtml.p(fullpath).
I think this is a simple yet effective method, but differs greatly from Prolint release 65 and earlier.
In Prolint <66 all help files were deployed as static htm files in directory "prolint/help", and for custom help you would write ".htxt" files in the "prolint/custom/help" directory and use the "Rebuild help" button to merge those files into the static htm files.
The reason why I prefer to open a live page at oehive.org, is because of its "open" spirit: you and everyone else can easily add comments to the help topics for everyone's benefit and improve the existing help.
Filters let you modify or delete warnings.
Directory "prolint/filters" contains 4gl procedure files, each .p file in this directory is a filter.
Each time when any rule creates a warning, the warning will first go through each filter before it is published to each outputhandler.
A filter can modify the description or severity fields, or it can mark the warning as 'filtered' in which case the outputhandler will probably ignore the warning.
Each filter has the same API which makes it easy to add your own custom filters. You can use the filters/_template.pp file as a boilerplate for creating a new filter.
The Prolint distribution already contains a couple of standard filters:
Directory prolint/settings or each of its subdirectories can contain a nowarn.lst file. In this text-file you can specify
a list of warnings you want to suppress.
This is convenient for sourcefiles (especially includefiles) you can't modify to add _proparse_ directives, like third-party includefiles
or src/adm2, for example.
For more details about the nowarn.lst file, see example file
Each profile directory (prolint/settings/profilename) can also contain an exclude.lst file.
This file works similar, but slightly different from nowarn.lst
exclude.lst works with file patterns with wildcards, both for filenames and rulenames. For example you can specify that all rules except rule "backslash" must be ignored in all files matching "third-party/*.i"
For more details about the exclude.lst file, see example file
Some rules must ignore warnings caused by code in AppBuilder-generated sections. Filter "ignoreab" figures out if a line is inside an ab-generated section.
An outputhandler must be located in directory prolint/outputhandlers, and has to be listed in
file prolint/outputhandlers/choices.d.
Columns in file prolint/outputhandlers/choices.d:
| "GUI" | this outputhandler will only run in a GUI session |
| "TTY" | this outputhandler will only run in a ChUI session |
| "*" | this outputhandler will run in any window-mode |
| "" | this outputhandler will only run in batch-mode |
Each outputhandler is loaded persistently by prolint.p, but prolint will never delete the procedure. The outputhandler has to delete itself when ready,
usually from within the event-procedure for event "Prolint_FinalizeResults".
The outputhandler subscribes to, and responds to (some) of the following published events:
PROCEDURE Prolint_InitializeResults : DEFINE INPUT PARAMETER pClearOutput AS LOGICAL NO-UNDO. END PROCEDURE.
Event Prolint_InitializeResults is published when prolint.p starts.
This is the right moment to create an output stream or XML-document or temp-table, or whatever kind of output you want to create.
pClearOutput=TRUE indicates that the existing output (logfile) needs to be emptied or that a new output stream (logfile) should be started.
pClearOutput=FALSE indicates that new lint-results should be appended to existing output (logfile).
PROCEDURE Prolint_List_Rules : DEFINE INPUT PARAMETER pRuleList AS CHARACTER NO-UNDO. /* comma-separated list of ruleid */ END PROCEDURE.Event Prolint_List_Rules is published to let you know which rules are selected in the current profile. This is a comma-separated list, not including the semi rule-id's used for system warnings like "prolint,proparse,compiler". This event is published once, after InitializeResults and before the first Status_Filestart.
PROCEDURE Prolint_Status_FileStart : DEFINE INPUT PARAMETER pSourceFile AS CHAR NO-UNDO. END PROCEDURE.Event Prolint_Status_FileStart is published to notify you when prolint starts to work on a new sourcefile, or actually on a new compilation-unit.
PROCEDURE Prolint_AddResult : DEFINE INPUT PARAMETER pCompilationUnit AS CHARACTER NO-UNDO. /* the sourcefile we're parsing */ DEFINE INPUT PARAMETER pSourcefile AS CHARACTER NO-UNDO. /* may be an includefile */ DEFINE INPUT PARAMETER pLineNumber AS INTEGER NO-UNDO. /* line number in pSourceFile */ DEFINE INPUT PARAMETER pDescription AS CHARACTER NO-UNDO. /* human-readable hint */ DEFINE INPUT PARAMETER pRuleID AS CHARACTER NO-UNDO. /* defines rule-program and maps to help */ DEFINE INPUT PARAMETER pSeverity AS INTEGER NO-UNDO. /* importance of this rule, scale 0-9 */ END PROCEDURE.Event Prolint_AddResult is published when prolint wants you to add something to the output (logfile).
PROCEDURE Prolint_Status_FileEnd : END PROCEDURE.Event Prolint_Status_FileEnd is published to notify you when prolint is done with the sourcefile that was earlier published in event Prolint_Status_FileStart.
PROCEDURE Prolint_FinalizeResults : END PROCEDURE.Event Prolint_FinalizeResults is published when prolint is ready.
PROCEDURE Prolint_Status_Action : DEFINE INPUT PARAMETER pAction AS CHAR NO-UNDO. END PROCEDURE.Event Prolint_Status_Action is probably only useful for logwin.w; parameter pAction is the text to show in the second panel of the statusbar.
PROCEDURE Prolint_Status_Profile : DEFINE INPUT PARAMETER pProfile AS CHAR NO-UNDO. END PROCEDURE.Event Prolint_Status_Profile sends you the name of the configuration profile that is used by Prolint.
PROCEDURE Prolint_Status_StopTimer : END PROCEDURE. PROCEDURE Prolint_Status_StartTimer : END PROCEDURE.Events Prolint_Status_StopTimer and Prolint_Status_StartTimer are used for finding out how long it takes to run rules: event Prolint_Status_StopTimer is published before compilation and parsing begins, Prolint_Status_StartTimer is published when compilation and parsing are ready which is also the moment that the loop "for each rule: run value(rule)..." begins.
If you have created a rule you should also create an help page for it. Your rule will probably warn progammers that some code statement is not quite good, and then those programmers will probably wonder why you think it is not good and how they can solve it.
These are the steps how to create a help page:
1. go to http://www.oehive.org/node/11
This page, simply titled "Rules" is the parent page of all help pages for rules. The page contains not much but an alphabetic list of rules, and at the bottom there is a link "Add child page". That's the link we need: click it. You will now get to see an input form for a new page.
2. in field "title" you should enter the rule-id. That is, when your rule is "memoryleak.p" then the rule-id is "memoryleak" so the title of the new page is also "memoryleak". All lowercase.
3. field "navigation" : do not select anything please.
4. field "keywords" : you dont need to enter anything except when the rule is a so-called "contributed rule". In that case please enter "contributed rules"
5. field "Body": here you enter anything you want to explain the rule to Prolint users. What I usually do is: explain what the rule is trying to detect, explain why the detected code is considered bad, do some suggestions how to fix it.
6. field "audience" (the list of toggle-boxes for groups):
please please please select the "Prolint" group!!
Unfortunately you can only select the "Prolint" group when you sourself are a member of that Prolint group, so you might have to become a member first.
7. field "URL path settings"
Here is some magic.... enter "prolint/rules/" + rule-id.
So for example: if the rule-id is "memoryleak" then enter "prolint/rules/memoryleak"
This ensures that the "Help" buttons in Prolint can browse to your help page.
8. Press the "Submit" button.
That's all, you have now created a help page for a rule!
All tests are performed by "rules", these are programs in directory prolint/rules.
This is where the actual knowledge about Progress source code review is implemented.
Each test is implemented in one rule, one rule implements one test.
All output is handled by outputhandlers, these are programs in directory prolint/outputhandlers.
An output handler receives results from rules and writes them to something else: for example to a window, to a
textfile in arbitrary format, to a pipe, to a database, whatever.
Customizing prolint will most likely mean: adding new rules and/or outputhandlers. If you do, please submit your customizations to
this Prolint Open Source project.
The invocation of the rules is coordinated by prolint/core/prolint.p.
You could basically summarize prolint.p to something like:
for each outputhandler:
run value(outputhandler) persistent.
/* each outputhandler subscribes to prolint messages */
end.
for each sourcefile:
for each rule:
run value(rule) (input sourcefile).
/* each rule publishes prolint messages */
end.
end.
prolint.p is designed to run silently: it does not ask questions, it does not display anything.
It gets all its information from input parameters and configuration files, it sends all its output to outputhandlers using publish/subscribe.
Input parameters for prolint/core/prolint.p are gathered by prolint/launch/start.p, which has no input parameter by itself.
prolint/launch/start.p invokes dialog prolint/core/selectfiles.w where an end-user can select files in a GUI dialog.
If you press button "Lint files" in the Results window, you actually
just run prolint/launch/start.p. If you would run the dialog directly, the dialog
would stay visible during the execution of prolint/core/prolint.p.
Variations of prolint/launch/start.p are no-brainers, see for example
prolint/launch/test.p which tells prolint.p to run a regression test on itself.
An outputhandler is a persistent procedure, launched by prolint.p, that receives information from prolint.p or from rules, because it is subscribed to
messages that are published by prolint.p and by rules. An outputhandler typically writes messages to a logfile. Different outputhandlers
can be used to write different file formats, even simultaneously. The Prolint results window (prolint/outputhandlers/logwin.w) is really just an outputhandler.
Because most rules do basically the same thing in different
variations, they can all use a set of ip's in prolint/core/lintsuper.p.
Lintsuper.p is attached to each rule as a super-procedure, although it is not constructed such that lintsuper.p is
a base ancestor rule-class where rules are inherited classes - it's better to regard lintsuper.p as just a regular support library where the
'super' option is used for programming pleasure.
Please review this proposal and add comments.
Current situation:
Currently Prolint supports two groups of rules: standard rules and custom rules. Standard rules are installed as part of the Prolint distribution. Custom rules don't come from the Prolint website; a custom rule is created by the Prolint user and never committed to the Prolint website and hence not available to other users.
When someone wants to share their custom rules, they have to be accepted by project admin (=Jurjen) and then wait until the next Prolint release.
Proposed new situation:
In addition to standard rules and custom rules, a new layer "contrib rules" will be added. Everyone can contribute their rules to the website and everyone can decide to download any number of contributed rules. Contributed rules are not installed as part of Prolint distribution, unless a contributed rule is "upgraded" to a standard rule.
This is more attractive for people who have custom rules to share, because these rules do not have to wait for acceptance and are published immediately. It is also attractive to Prolint users to be able to choose from a public collection of custom rules, and it is attractive for myself because I won't have the burden to accept/review/reject rules.
Subversion:
In te subversion repository for prolint, a path "/trunk/contribs/rules" will be added and user "guest" will be authorized to read/write in this path. The password for "guest" will be announced here, so anyone can commit their rules to this path. The guest user is not authorized to commit anything outside the "/trunk/contribs/rules" path.
Definitions:
Each rule (example.p) must come with its own definition file (example.rule). The definition file contains the definitions for this one rule, e.g. description, severity, category, useProparse, useXref, etc.
Users will download the rule+definition pair to their "prolint/contribs/rules" directory - no need to maintain rules.d.
The format of the definition file must be something that can be imported very quickly yet easy to understand for humans.
Help:
Someone who contributes a rule should also add a help page, which is a child-page of http://www.oehive.org/prolint/rules
That help page should describe the purpose of the rule and should also identify the rule as a contributed rule that can be downladed from the subversion contribs path.
In addition, the help page should be attached to the "contributed rules" keyword, so all contributed rules can be easily listed.
Shop for rules:
Visitors will be able to discover contributed rules in several ways:
Search order:
Prolint will search rule definitions in the following order:
1. prolint/contribs/rules
2. extend and override the results from (1) by prolint/rules
3. extend and override the results from (2) by prolint/custom/rules
Execution order:
Prolint will search rule code in the following order:
1. prolint/custom/rules
2. when not found, search the rule in turbolint
3. when not found, search the rule in prolint/rules
4. when not found, search the rule in prolint/contribs/rules
Please comment??
Thanks, Jurjen
When you add of change something to any Prolint source, you can do a regression test to see if you broke something.
Before you can run the regression tests, you will first need to create a database named "prolintest.db" in directory "prolint/regrtest/db". A schema definition file for this database is provided: "prolint/regrtest/db/prolintest.df". Simply create a new database from empty and import this df file. This database does not need any data, areas are not important, it just needs to exist so the test code can compile. Prolint will automatically connect to this database in single user mode, and will automatically disconnect when the regression test is over.
Now, when the prolintest database is created, you can launch the regression test using:
RUN prolint/launch/test.p
In the end you should see a window containing the following text:
Comparing files prolint.log and EXPECT.LOG FC: no differences encountered
This means that everything is still working as expected.
How it works:
prolint/launch/test.p launches a Prolint session that checks every sourcefile in directory "prolint/regrtest" and, when you are using OpenEdge 10, also directory "prolint/regrtest-oo" which contains OO classes.
The warnings from this Prolint session are logged to a text file (prolint.log) and this text file is then compared to the expected warnings in file "prolint/regrtest/expect.log" and "prolint/regrtest-oo/expect.log".
These files are simply proliint.log files from earlier sessions. Simple, but effective.
The split into two directories, regrtest and regrtest-oo, is to make sure that Progress 9 users can also run the regresssion test.
If you add a new rule, it would be great if you also add test-cases for this rule to directory "prolint/regrtest" (or "prolint/regrtest-oo" if it is object oriented code).
run prolint/core/prolint.p(...) analyzes one or more sourcefiles, it is the entrypoint of all parsing.
Because prolint.p requires a couple of input parameters you will probably prefer to run a "wrapper"-procedure that first assigns those parameters and then passes them to prolint.p.
Let's first look at an example "wrapper", the parameters are explained later in this page.
procedure prolint/launch/start.p is an example of a "wrapper", it first runs a dialog where you can choose values for all parameters and then it calls prolint.p.
start.p should work in Progress 9 and OpenEdge 10, GUI or ChUI (and Progress 8 if you have Prolint release 63)
Here is a simple example with no user interface: it scans the contents of directory "d:\myproject" and runs prolint
DEFINE VARIABLE fname AS CHARACTER NO-UNDO.
DEFINE VARIABLE fullpath AS CHARACTER NO-UNDO.
DEFINE VARIABLE attribs AS CHARACTER NO-UNDO.
DEFINE TEMP-TABLE tt_files NO-UNDO
FIELD SourceFile AS CHARACTER.
/* find all sourcefiles in directory */
INPUT FROM OS-DIR ("d:\myproject").
REPEAT:
IMPORT fname fullpath attribs.
IF NOT (attribs MATCHES "*D*") THEN
IF (fname MATCHES "*~~.p") OR (fname MATCHES "*~~.w") THEN DO:
CREATE tt_files.
ASSIGN tt_files.SourceFile = fullpath.
END.
END.
INPUT CLOSE.
/* now lint all of them, send output to prolint.log (=profile "batchrun") */
IF CAN-FIND(FIRST tt_files) THEN
RUN prolint/core/prolint.p ("",
THIS-PROCEDURE:HANDLE,
"batchrun",
TRUE).
/* You could simply pass the temp-table handle, but
* that doesn't work in Progress version 8:
*
* IF CAN-FIND(FIRST tt_files) THEN
* RUN prolint/core/prolint.p ("",
* TEMP-TABLE tt_files:HANDLE,
* "batchrun",
* TRUE).
*/
RETURN.
PROCEDURE GetFirstLintSource :
/* purpose: prolint.p calls this ip to ask for the first sourcefile to analyze.
return ? if you don't have any sourcefiles. */
DEFINE OUTPUT PARAMETER pSourceFile AS CHARACTER NO-UNDO.
FIND FIRST tt_sourcefiles NO-ERROR.
IF AVAILABLE tt_sourcefiles THEN
pSourceFile = tt_sourcefiles.SourceFile.
ELSE
pSourceFile = ?.
END PROCEDURE.
PROCEDURE GetNextLintSource :
/* purpose: prolint.p calls this ip to ask for the next sourcefile to analyze.
return ? to stop */
DEFINE OUTPUT PARAMETER pSourceFile AS CHARACTER NO-UNDO.
FIND NEXT tt_sourcefiles NO-ERROR.
IF AVAILABLE tt_sourcefiles THEN
pSourceFile = tt_sourcefiles.SourceFile.
ELSE
pSourceFile = ?.
END PROCEDURE.
|
Note that the above example is just an example, an easier way to get almost the same result is:
RUN prolint/core/prolint.p ("d:\myproject",
?,
"batchrun",
TRUE).
|
Two differences with the first example:
1. Prolint will scan directory d:\myproject and all its subdirectories
2. Prolint will not only look for .p and .w extensions, but all extensions specified in prolint.properties.p
input pSourcefile (as character)
The filename of a sourcefile you want to lint. This parameter is convenient if you want to lint just one single sourcefile.
If you want to lint multiple sourcefiles it is recommended to set SourceFile="" and use hSourcefileList instead.
pSourcefile can also specify a directory. In that case Prolint will search every compilation-unit in that directory and all its subdirectories recursive. Compilation-units are recognized by file extension; the list of file extensions is "*.p,*.pp,*.w,*.cls" by default but you can change this using the prolint.properties.p file.
pSourcefile can also specify a comma-separated list of sourcefiles and/or directories.
input hSourcefileList (as handle)
The handle to a procedure or to a temp-table, or the unknown value. Set this parameter if you want prolint to analyze multiple sourcefiles in a single run.
If it is a PROCEDURE:HANDLE, prolint requires that this procedure contains two internal procedures: procedure GetFirstLintSource(output pSourceFile) and procedure GetNextLintSource(output pSourceFile). Prolint runs these internal procedures in hSourcefileList until one of them returns the unknown value.
If it is a TEMP-TABLE:HANDLE, then prolint assumes this temp-table contains one or more records, where each record contains the name of one sourcefile in a field with fieldname="SourceFile".
input pCustomProfile (as character)
The name of a profile, specifying which rules and outputhandlers to run.
input pClearOutput (as logical)
Specifies if you want to append warnings from Prolint to existing output, or replace existing output by new output.
if pClearOutput=TRUE, the outputhandlers will overwrite existing output.
if pClearOutput=FALSE, the outputhandlers will append to existing output.
-
The Progress Appbuilder already has a menu-item "Check Syntax", you can also add a menu-item "Prolint" for the extensive code inspection of Prolint.
To create the new menu-item you will have to install a custom event. This is how: locate file "gui/adecomm/_adeevnt.p" in the DLC directory and add this single line to it:
{prolint/ab/custom_evnt.i} You may have to compile...save adecomm/_adeevnt.p and restart the Appbuilder before the change has effect.
Now, when you open a file in the Appbuilder and choose the Prolint menu-item, the currently selected file will be inspected by Prolint. You can configure a profile with the name "Appbuilder" to specify which rules and outputhandlers are used.
Notice however that only the saved file will be inspected, not the version in memory that may be different from the saved version!
Prolint integrates with "ED for Windows" in three ways:
The first feature is configured in file prolint/settings/exteditor.cfg, see "settings".
The second feature requires proed4w, which is another free tool from global-shared.com. The following screen-shot shows proed4w in action:

You see a new toolbar-button (the white document with the red exclamation mark), when you press it the blue "Build results" pane will pop up and show
results from Prolint. This "Build results" pane can be used for navigating through the sourcefile, but you can also use the "previous error" and "next error" buttons.
Surf to "ProED4W" for download and general setup-instructions.
After you have installed proed4w as outlined in its general setup-instructions, you have to make one final setting in Prolint:
make sure Prolint has a profile named "ed4win" which uses the special outputhandler (also named "ed4win").
This too requires the proed4w tool.
The disadvantage of method (2) is that warnings appear in the order by which they are discovered: "BY rule BY sourcefile BY line".
It may be more convenient to have them appear in a different order.
The Prolint Results window allows you to sort warnings on all columns, and also allows you to specify a filter.
When you import warnings from the Results window into ED, the order and filter will be applied.
In ED for Windows you must have created a build-title named "Prolint-logwin" once:
To run it, just make sure the Prolint Results window is running and that the "Proed4w Server" is also running in the same Progress session.
In ED, run the Build title we've just described. That's all!
PRO4m is a commercial product that creates HTML reports about your projects, looks for unused database objects, and more.
You can find information about PRO4m at www.progress-plus.com.
PRO4m can call Prolint to incorporate the results from Prolint in its HTML reports. If you want to give it a try download "3PRO" from www.progress-plus.com.
3PRO combines PRO4m, Proparse and Prolint in a single setup for your convenience.
Hot from the Prolint laboratory: the proof-of-concept work-in-progress alpha-prototype of Prolint inside OpenEdge Architect.
The purpose is to make it very easy and super-productive to use Prolint while you are working on your OpenEdge project in OpenEdge Architect. You need OpenEdge Architect 10.1C for this.
The toolbar gets a "run Prolint" button, somewhere close to the Run and Debug buttons, and when you press that Prolint button you start to lint the currently selected resource. That can be:
- the file in the active editor, or
- the file that is selected in the Resources treeview, or
- the directory that is selected in the Resources treeview, including all files and subdirectories, recursive.
The Prolint results are, as usual, displayed in a Progress window with a browse widget, but what's new is that this window is embedded in the OpenEdge Architect/Eclipse IDE. As shown in the following image:

You want to give it a try? There is no automatic setup yet, you need to do a couple of simple things manually. Here they are: