{iframe:src=http://update.sonarsource.org/plugins/delphi.html|width=700|height=250|frameborder=0}
Your browser does not support iframes.
{iframe} |
Delphi Sonar plugin enables analysis of projects written using Delphi or Pascal. It was tested with projects written in Delphi 6, 7, 2006 and XE.
It is using grammar in ANTLR v3 format. It is extended on grammar found at http://www.dragonkiller.nl/Delphi/delphi2009.txt
It is compatible with the Issues Report plugin to run pre-commit local analysis.
To launch a Sonar analysis of your Delphi project, use the Sonar Runner.
A sample project is available on github that can be browsed or downloaded: /projects/languages/delphi/delphi-sonar-runner.
Maven and Ant can also be used to launch analysis on Delphi projects.
You can find a sample project in "src/Sample/SampleProject". It contains an Ant script, which you can use to do the analysis. You must have ANT installed.
Install the Delphi plugin on your Sonar instance, and type "ant sonar" from sample project directory in order to try the plugin.
See Metrics documentation page.
All assumptions in grammar file are commented with //ASSUMPTION comment.
Below is the list of the most common grammar problems. You can also look at file GrammarTest.pas to get more detailed information.
On e: exception do
Begin
End
If you want to debug grammar from AntlrWorks, do the following:
You should put transformed DUnit xml files to directory specified in build.xml file, under sonar.surefire.reportsPath parameter. You can specify multiply directories separated by ‘,’. Then all specified directories will be parsed. The path can be either absolute or relative to the project main path.
The xml files should be renamed with “TEST-“ prefix, example: “dunit.xml” -> “TEST-dunit.xml”.
CodeCoverageSensor class is responsible for running CC analysis. It creates a parser that connects to specified data base holding AQTime generated CC report. Connection properties can be specified in a build.xml or pom.xml file (see below). If parser can’t connect to the data base, analysis is skipped.
You can specify exclude directories in build xml file, under sonar.delphi.codecoverage.excluded parameter. The files in specified directories will be not checked for code coverage.
This class prepares source code for parsing. It does the following:
- Parse preprocessor definitions (using DefineResolver class)
- Add include files (using IncludeResolver class)
- “Fix” the code as explained in code assumption 1 (using SourceFixcerResolver class).
- Feed ANTLR parser with lowercase characters (code assumption 2).
To properly do this things, the class firstly searches for areas that should not be parsed: comments and single quoted strings. Why? For example, you can have such piece of code:
X := 5; //{$include file.inc}S := ‘my {$include file.inc} string’;Without recognizing which areas to exclude, the parser would simply copy-paste the file “file.inc” into a comment or a string, and this would produce an error.
There are few additional project parameters that you can set in Ant’s build.xml.
KEY | DESCRIPTION | EXAMPLE |
sonar.delphi.sources.excluded | Excluded directories, they won’t be parsed and metrics won’t be calculated for them. Path’s can be relative to main project directory or absolute. Separate them with ‘,’. Default value is “”. | <property key="sonar.delphi.sources.excluded " value="excluded\directory, another\excluded,c:\something" />
|
sonar.delphi.codecoverage.excluded | Code coverage excluded directories list. Files in those directories will not be checked for code coverage. Default value is “”. | <property key="sonar.delphi.codecoverage.excluded" value="cc\test\excluded,c:\sth" /> |
sonar.delphi.sources.include | Path to include directories for files included with {$include} or {$i} directive. Default value is “”. | <property key="sonar.delphi.sources.include" value="includes_dir,includes_dir2" /> |
sonar.delphi.sources.include.extend | Should we extend (copy-paste) include files? Possible values are “true” or “false”. Default value is “true”. | <property key="sonar.delphi.sources.include.extend" value="true"> |
sonar.delphi.sources.projects | Project file. If provided, will be parsed for include lookup path, project source files and preprocessor definitions. Default value is “”. | <property key=" sonar.delphi.sources.project" value="projects\myProject.dproj"> |
sonar.delphi.sources.workgroup | Workgroup file. If provided, will be parsed, then all *.dproj files found in workgroup file will be parsed. | <property key=" sonar.delphi.sources.workgroup" value="projects\All.groupproj"> |
sonar.delphi.codecoverage.aqtime.jdbc.driver | Class name for JDBC driver. Default value is “net.sourceforge.jtds.jdbc.Driver” | <property key="sonar.delphi.codecoverage.aqtime.jdbc.driver" value="net.sourceforge.jtds.jdbc.Driver" /> |
sonar.delphi.codecoverage.aqtime.jdbc.url | Database connection url. Default value is “”. | <property key="sonar.delphi.codecoverage.aqtime.jdbc.url" value="jdbc:jtds:sqlserver://localhost" /> |
sonar.delphi.codecoverage.aqtime.jdbc.user | Database user name. Default value is “”. | <property key="sonar.delphi.codecoverage.aqtime.jdbc.user" value="admin" /> |
sonar.delphi.codecoverage.aqtime.jdbc.password | Database user password. Default value is “”. | <property key="sonar.delphi.codecoverage.aqtime.jdbc.password" value="pass" /> |
| sonar.delphi.codecoverage.aqtime.jdbc.prefix | Database prefix for connecting to AQTime database. Default value is "". | <property key="sonar.delphi.codecoverage.aqtime.jdbc.prefix" value="CC.dbo." /> |
If you want to make a custom PMD rule, you can do it in two ways:
WRITE YOUR OWN CLASS
Create rule class, that extends from org.sonar.plugins.delphi.pmd.rules.DelphiRule class. You will need to overload visit(DelphiPMDNode node, Object data) method. You will have the current ast tree node and whole ast tree to your disposal. If you want to save a violation, invoke addViolation(Object data, DelphiPMDNode node) method.
If you want to initialize some class variables at start of each file, overload the init() method. Look at the org.sonar.plugins.delphi.pmd.rules package for sample classes.
After you write your class, modify the “rules.xml” and “default-delphi-profile.xml”, simply add your class to the list.
WRITE XPATH SENTENCE
You can write an XPath sentence which will parse the whole file. Open the “rules.xml” file, copy one of the XPath rules already available and change the “xpath” property to your XPath string. Don’t forget to add the rule to “default-delphi-profile.xml”. That’s it!
For full summary (description, examples) of custom PMD rules, do the following: execute Sonar -> Configuration -> Default Delphi Profile and browse the rules under Delphi profile.
List of implemented rules, as follows:
RULE NAME | RULE PRIORITY |
1. Then Try Rule (you should place ‘begin’ before ‘try’) | 3 |
2. One Class Per File Rule (one class per file permitted) | 3 |
3. Inherited Method With No Code Rule (method that only inherits behavior) | 2 |
4. Empty Except Block Rule (empty ‘except’ block, catching no exceptions) | 1 |
5. Empty Interface Rule (empty interface) | 2 |
6. Empty Then Statement Rule (empty ‘then’ statement) | 2 |
7. Empty Begin Statement Rule (empty ‘begin’ .. ‘end’ statement) | 2 |
8. Empty Else Statement Rule (empty ‘else’ statement) | 2 |
9. Too Long Method Rule (method too long, above certain line limit) | 3 |
10. Too Many Arguments Rule (to many function/procedure arguments) | 3 |
11. Too Many Variables Rule (to many variables in a function/procedure) | 3 |
12. No Semi After Overload Rule (no semicolon ‘;’ after ‘overload’ keyword) | 4 |
13. No Function Return Type Rule (function with no return type specified) | 3 |
14. Interface Name Rule (interface name should begin with ‘I’ letter) | 4 |
15. Class Name Rule (class name should begin with ‘T’ letter) | 4 |
16. Record Name Rule (record name should begin with ‘T’ letter) | 4 |
17. Catching General Exception Rule (catching Exception class in ‘except’ statement) | 3 |
18. Raising General Exception Rule (raising Exception class in ‘raise’ statement) | 3 |
19. Avoid Out Parameter Rule (using ‘out’ arguments) | 4 |
20. If True Rule (convert ‘if(x=true) then’ to ‘if (x) then’) | 4 |
21. If Not False Rule (convert ‘if not (x = false) then’ to ‘if (x) then’ | 4 |
22. Public Field Rule (class fields should NOT be public) | 4 |
23. Avoid Unused Method Parameters Rule (avoid making function arguments that are not used in body) | 3 |
24. No Interface Guid (no Guid at interface) | 5 |
25. If Assigned And Free (before calling ‘Free’ you don’t need to check for variable assignment ‘x <> nil’) | 4 |
26. Project File No Functions Rule (.dpr file should not contain procedures or functions) | 3 |
27. Project File No Variables Rule (.dpr file should not contain variables) | 3 |
28. Type Alias Rule (avoid using type aliases) | 4 |
29. Uppercase Reserved Keywords Rule (avoid using uppercase reserved keywords) | 5 |
30. Mixed Names Rule (avoid case mixing names of functions / variables) | 4 |
31. Unused Unit Rule (searches for units that are not referenced in other units) | 3 |
32. Unused Function Rule (searches for functions/procedures that are not used by other functions/procedures) | 3 |
33. Constructor Without Inherited Statement Rule (constructor does not contain ‘inherited’ statement) | 2 |
34. Destructor Without Inherited Statement Rule (destructor does not contain ‘inherited’ statement) | 2 |
35. No ‘begin’ after ‘do Statement Rule | 4 |
36. ‘With’ after ‘do’ statement Rule | 3 |