The following schema fragment specifies the expected content contained within this class. 20 | * 21 | *
22 | * 23 | *
24 | * <simpleType name="ruleMode">
25 | * <restriction base="{http://www.w3.org/2001/XMLSchema}string">
26 | * <enumeration value="Default"/>
27 | * <enumeration value="Group"/>
28 | * <enumeration value="Single"/>
29 | * </restriction>
30 | * </simpleType>
31 | *
32 | */
33 | @XmlType(name = "ruleMode")
34 | @XmlEnum
35 | public enum RuleMode {
36 | @XmlEnumValue("Default")
37 | DEFAULT("Default"),
38 | @XmlEnumValue("Group")
39 | GROUP("Group"),
40 | @XmlEnumValue("Single")
41 | SINGLE("Single");
42 | private final String value;
43 |
44 | RuleMode(String v) {
45 | value = v;
46 | }
47 |
48 | public String value() {
49 | return value;
50 | }
51 |
52 | public static RuleMode fromValue(String v) {
53 |
54 | if (StringUtils.isBlank(v)) {
55 | return RuleMode.DEFAULT;
56 | }
57 | for (RuleMode c : RuleMode.values()) {
58 | if (c.value.equalsIgnoreCase(v)) {
59 | return c;
60 | }
61 | }
62 | throw new IllegalArgumentException(v);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/examples/1-tsql/00-installTools.ps1:
--------------------------------------------------------------------------------
1 | Add-Type -AssemblyName System.IO.Compression.FileSystem
2 |
3 | function Uzip-File {
4 | param( [string]$ziparchive, [string]$extractpath )
5 | [System.IO.Compression.ZipFile]::ExtractToDirectory( $ziparchive, $extractpath )
6 | }
7 |
8 | $baseToolsDir = "$PSScriptRoot\tools";
9 | New-Item -ItemType Directory -Force -Path $baseToolsDir
10 |
11 | function Setup-SqlCodeGuard {
12 | $url = "http://download.red-gate.com/SQLCodeGuardCmdLine.zip"
13 | $output = "$baseToolsDir\SQLCodeGuardCmdLine.zip";
14 | $outputDir = "$baseToolsDir\SQLCodeGuardCmdLine"
15 | [Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
16 | $WebClient = New-Object System.Net.WebClient
17 | $WebClient.DownloadFile($url,$output)
18 | Uzip-File -ziparchive $output -extractpath $outputDir
19 | Write-output "Extracted SQLCodeGuardCmdLine to $outputDir"
20 | }
21 |
22 | function Setup-SonarScanner {
23 | $url = "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.6.2.2472-windows.zip"
24 | $output = "$baseToolsDir\scanner.zip";
25 | $outputDir = "$baseToolsDir\sonar-scanner"
26 | [Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
27 | $WebClient = New-Object System.Net.WebClient
28 | $WebClient.DownloadFile($url,$output)
29 | Uzip-File -ziparchive $output -extractpath $outputDir
30 | Write-output "Extracted sonar-scanner to $outputDir"
31 | }
32 |
33 | function Setup-SQLCover {
34 | $url = "https://github.com/GoEddie/SQLCover/releases/download/0.4.1/SQLCOver.0.4.1.zip";
35 | $output = "$baseToolsDir\sqlCover.zip";
36 | $outputDir = "$baseToolsDir\SQLCover"
37 | [Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
38 | $WebClient = New-Object System.Net.WebClient
39 | $WebClient.DownloadFile($url,$output)
40 | Uzip-File -ziparchive $output -extractpath $outputDir
41 | Write-output "Extracted SQLCover to $outputDir"
42 |
43 | }
44 | Setup-SqlCodeGuard
45 | Setup-SQLCover
46 | Setup-SonarScanner
--------------------------------------------------------------------------------
/examples/5-tsql/00-installTools.ps1:
--------------------------------------------------------------------------------
1 | Add-Type -AssemblyName System.IO.Compression.FileSystem
2 |
3 | function Uzip-File {
4 | param( [string]$ziparchive, [string]$extractpath )
5 | [System.IO.Compression.ZipFile]::ExtractToDirectory( $ziparchive, $extractpath )
6 | }
7 |
8 | $baseToolsDir = "$PSScriptRoot\tools";
9 | New-Item -ItemType Directory -Force -Path $baseToolsDir
10 |
11 | function Setup-SqlCodeGuard {
12 | $url = "http://download.red-gate.com/SQLCodeGuardCmdLine.zip"
13 | $output = "$baseToolsDir\SQLCodeGuardCmdLine.zip";
14 | $outputDir = "$baseToolsDir\SQLCodeGuardCmdLine"
15 | [Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
16 | $WebClient = New-Object System.Net.WebClient
17 | $WebClient.DownloadFile($url,$output)
18 | Uzip-File -ziparchive $output -extractpath $outputDir
19 | Write-output "Extracted SQLCodeGuardCmdLine to $outputDir"
20 | }
21 |
22 | function Setup-SonarScanner {
23 | $url = "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.6.2.2472-windows.zip"
24 | $output = "$baseToolsDir\scanner.zip";
25 | $outputDir = "$baseToolsDir\sonar-scanner"
26 | [Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
27 | $WebClient = New-Object System.Net.WebClient
28 | $WebClient.DownloadFile($url,$output)
29 | Uzip-File -ziparchive $output -extractpath $outputDir
30 | Write-output "Extracted sonar-scanner to $outputDir"
31 | }
32 |
33 | function Setup-SQLCover {
34 | $url = "https://github.com/GoEddie/SQLCover/releases/download/0.4.1/SQLCOver.0.4.1.zip";
35 | $output = "$baseToolsDir\sqlCover.zip";
36 | $outputDir = "$baseToolsDir\SQLCover"
37 | [Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
38 | $WebClient = New-Object System.Net.WebClient
39 | $WebClient.DownloadFile($url,$output)
40 | Uzip-File -ziparchive $output -extractpath $outputDir
41 | Write-output "Extracted SQLCover to $outputDir"
42 |
43 | }
44 | Setup-SqlCodeGuard
45 | Setup-SQLCover
46 | Setup-SonarScanner
--------------------------------------------------------------------------------
/src/sonar-sql-plugin/src/main/java/org/antlr/sql/dialects/SnowflakeDialect.java:
--------------------------------------------------------------------------------
1 | package org.antlr.sql.dialects;
2 |
3 | import org.antlr.sql.dialects.snowflake.SnowflakeLexer;
4 | import org.antlr.sql.dialects.snowflake.SnowflakeParser;
5 | import org.antlr.sql.dialects.snowflake.SnowflakeParser.Group_by_clauseContext;
6 | import org.antlr.sql.dialects.snowflake.SnowflakeParser.Order_by_clauseContext;
7 | import org.antlr.sql.dialects.snowflake.SnowflakeParser.PredicateContext;
8 | import org.antlr.sql.dialects.snowflake.SnowflakeParser.Select_statementContext;
9 | import org.antlr.sql.dialects.snowflake.SnowflakeParser.Update_statementContext;
10 | import org.antlr.v4.runtime.CharStream;
11 | import org.antlr.v4.runtime.CommonTokenStream;
12 | import org.antlr.v4.runtime.Lexer;
13 | import org.antlr.v4.runtime.tree.ParseTree;
14 |
15 | public class SnowflakeDialect extends BaseDialect {
16 |
17 | @Override
18 | protected Lexer getLexer(CharStream charStream) {
19 | return new SnowflakeLexer(charStream);
20 | }
21 |
22 | @Override
23 | protected ParseTree getRoot(CommonTokenStream stream) {
24 | SnowflakeParser p = new SnowflakeParser(stream);
25 | p.removeErrorListeners();
26 | return p.snowflake_file();
27 | }
28 |
29 | @Override
30 | protected DialectLanguageTypesMap getTypesMap() {
31 | return new DialectLanguageTypesMap()
32 | .addCommentToken(SnowflakeLexer.SQL_COMMENT)
33 | .addCommentToken(SnowflakeLexer.LINE_COMMENT)
34 | .addCommentToken(SnowflakeLexer.LINE_COMMENT_2)
35 | .addStringToken(SnowflakeLexer.STRING)
36 | .addComplexityType(PredicateContext.class)
37 | .addCognitiveComplexityType(Order_by_clauseContext.class)
38 | .addCognitiveComplexityType(PredicateContext.class)
39 | .addCognitiveComplexityType(Select_statementContext.class)
40 | .addCognitiveComplexityType(Update_statementContext.class)
41 | .addCognitiveComplexityType(Group_by_clauseContext.class);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/sonar-sql-plugin/src/test/java/org/antlr/sql/tools/PluginRulesPrinter.java:
--------------------------------------------------------------------------------
1 | package org.antlr.sql.tools;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Arrays;
5 | import java.util.HashMap;
6 | import java.util.List;
7 | import java.util.Map;
8 | import java.util.Map.Entry;
9 | import org.antlr.sql.dialects.Dialects;
10 | import org.antlr.sql.dialects.SQLDialectRules;
11 | import org.sonar.plugins.sql.models.rules.Rule;
12 | import org.sonar.plugins.sql.models.rules.SqlRules;
13 |
14 | public class PluginRulesPrinter {
15 | public static void main(String[] args) {
16 | ListSupported dialects: " 41 | + String.join(",", dialects.toArray(new String[0])) 42 | + "
"); 43 | System.out.println(r.getDescription()); 44 | System.out.println(); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/sonar-sql-plugin/src/test/java/org/sonar/plugins/sql/fillers/CpdTokensFillerTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.sql.fillers; 2 | 3 | import java.io.File; 4 | import java.util.List; 5 | import org.antlr.sql.dialects.Dialects; 6 | import org.antlr.sql.models.AntlrContext; 7 | import org.apache.commons.io.FileUtils; 8 | import org.junit.Assert; 9 | import org.junit.Rule; 10 | import org.junit.Test; 11 | import org.junit.rules.TemporaryFolder; 12 | import org.sonar.api.batch.fs.internal.DefaultInputFile; 13 | import org.sonar.api.batch.fs.internal.TestInputFileBuilder; 14 | import org.sonar.api.batch.sensor.cpd.internal.TokensLine; 15 | import org.sonar.api.batch.sensor.internal.SensorContextTester; 16 | import org.sonar.plugins.sql.Constants; 17 | 18 | public class CpdTokensFillerTest { 19 | 20 | @Rule public TemporaryFolder folder = new TemporaryFolder(); 21 | 22 | @Test 23 | public void test() throws Exception { 24 | SensorContextTester ctxTester = SensorContextTester.create(folder.getRoot()); 25 | ctxTester.fileSystem().setWorkDir(folder.getRoot().toPath()); 26 | 27 | File baseFile = folder.newFile("test.sql"); 28 | 29 | FileUtils.copyURLToFile(getClass().getResource("/tsql/sample1.sql"), baseFile); 30 | String contents = FileUtils.readFileToString(baseFile); 31 | 32 | DefaultInputFile ti = 33 | new TestInputFileBuilder("test", folder.getRoot(), baseFile) 34 | .initMetadata(contents) 35 | .setLanguage(Constants.languageKey) 36 | .setContents(contents) 37 | .setProjectBaseDir(folder.getRoot().toPath()) 38 | .build(); 39 | ctxTester.fileSystem().add(ti); 40 | 41 | AntlrContext antlrContext = Dialects.TSQL.parse(FileUtils.readFileToString(baseFile)); 42 | CpdTokensFiller filler = new CpdTokensFiller(); 43 | filler.fill(ti, ctxTester, antlrContext); 44 | ListThe following schema fragment specifies the expected content contained within this class. 20 | * 21 | *
22 | * 23 | *
24 | * <simpleType name="textCheckType">
25 | * <restriction base="{http://www.w3.org/2001/XMLSchema}string">
26 | * <enumeration value="Default"/>
27 | * <enumeration value="Contains"/>
28 | * <enumeration value="Regexp"/>
29 | * <enumeration value="Strict"/>
30 | * </restriction>
31 | * </simpleType>
32 | *
33 | */
34 | @XmlType(name = "textCheckType")
35 | @XmlEnum
36 | public enum TextCheckType {
37 | @XmlEnumValue("Default")
38 | DEFAULT("Default"),
39 | @XmlEnumValue("Contains")
40 | CONTAINS("Contains"),
41 | @XmlEnumValue("Regexp")
42 | REGEXP("Regexp"),
43 | @XmlEnumValue("Strict")
44 | STRICT("Strict");
45 | private final String value;
46 |
47 | TextCheckType(String v) {
48 | value = v;
49 | }
50 |
51 | public String value() {
52 | return value;
53 | }
54 |
55 | public static TextCheckType fromValue(String v) {
56 | if (StringUtils.isBlank(v)) {
57 | return TextCheckType.DEFAULT;
58 | }
59 |
60 | for (TextCheckType c : TextCheckType.values()) {
61 | if (c.value.equalsIgnoreCase(v) || c.name().equalsIgnoreCase(v)) {
62 | return c;
63 | }
64 | }
65 | throw new IllegalArgumentException(v);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/sonar-sql-plugin/src/main/java/org/antlr/sql/sca/matchers/IndexMatcher.java:
--------------------------------------------------------------------------------
1 | package org.antlr.sql.sca.matchers;
2 |
3 | import org.antlr.sql.sca.nodes.IParsedNode;
4 | import org.sonar.plugins.sql.models.rules.RuleDistanceIndexMatchType;
5 | import org.sonar.plugins.sql.models.rules.RuleImplementation;
6 |
7 | public class IndexMatcher implements IMatcher {
8 |
9 | @Override
10 | public boolean match(IParsedNode node, RuleImplementation rule) {
11 | if (rule.getIndex() == 0) {
12 | return true;
13 | }
14 | if (rule.getIndex() > 0) {
15 | int val = node.getIndex();
16 | if (val == 0) {
17 | val = node.getGlobalIndex();
18 | }
19 | if (rule.getIndexCheckType() == RuleDistanceIndexMatchType.LESS) {
20 | if (val > rule.getIndex()) {
21 | return false;
22 | }
23 | }
24 | if (rule.getIndexCheckType() == RuleDistanceIndexMatchType.EQUALS) {
25 | if (val != rule.getIndex()) {
26 | return false;
27 | }
28 | }
29 | if (rule.getIndexCheckType() == RuleDistanceIndexMatchType.MORE) {
30 | if (val < rule.getIndex()) {
31 | return false;
32 | }
33 | }
34 | }
35 | if (rule.getIndex() < 0) {
36 | int val = node.getIndex2();
37 | if (val == 0) {
38 | val = node.getGlobalIndex();
39 | }
40 | if (rule.getIndexCheckType() == RuleDistanceIndexMatchType.LESS) {
41 | if (val > rule.getIndex()) {
42 | return false;
43 | }
44 | }
45 | if (rule.getIndexCheckType() == RuleDistanceIndexMatchType.EQUALS) {
46 | if (val != rule.getIndex()) {
47 | return false;
48 | }
49 | }
50 | if (rule.getIndexCheckType() == RuleDistanceIndexMatchType.MORE) {
51 | if (val < rule.getIndex()) {
52 | return false;
53 | }
54 | }
55 | }
56 | return true;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/sonar-sql-plugin/src/main/java/org/sonar/plugins/sql/Constants.java:
--------------------------------------------------------------------------------
1 | package org.sonar.plugins.sql;
2 |
3 | public final class Constants {
4 | public static final String languageKey = "sql";
5 |
6 | public static final String PLUGIN_SQL_DIALECT = "sonar.sql.dialect";
7 |
8 | public static final String PLUGIN_SQL_SCA_TIMEOUT = "sonar.sql.sca.timeout";
9 |
10 | public static final long PLUGIN_SQL_SCA_TIMEOUT_DEFAULT = 3600l;
11 |
12 | public static final String PLUGIN_SUFFIXES = "sonar.sql.file.suffixes";
13 |
14 | public static final String PLUGIN_SQL_EXTERNAL_RULES_SUFFIX = "sonar.sql.rules.suffixes";
15 |
16 | public static final String PLUGIN_SQL_RULES_SKIP = "sonar.sql.rules.skip";
17 |
18 | public static final String PLUGIN_SQL_EXTERNAL_RULES_SEARCH_PATH = "sonar.sql.rules.path";
19 |
20 | public static final String PLUGIN_SQL_EXTERNAL_RULES_SEARCH_PATH_DEFAULT = ".";
21 |
22 | public static final String PLUGIN_SQL_EXTERNAL_RULES_SUFFIXES_DEFAULT = ".customRules";
23 |
24 | public static final String TSQL_MS_ISSUES = "sonar.sql.tsql.ms.report";
25 |
26 | public static final String TSQL_MS_ISSUES_DEFAULT = "staticcodeanalysis.results.xml";
27 |
28 | public static final String TSQL_MS_REPO_KEY = "tsql-ms";
29 |
30 | public static final String TSQL_MS_ENGINEID = "tsql-ms";
31 |
32 | public static final String TSQL_CG_ENGINEID = "tsql-cg";
33 |
34 | public static final String TSQL_CG_PATH_DEFAULT =
35 | "C:\\Program Files\\SQLCodeGuardCmdLine\\SqlCodeGuard40.Cmd.exe";
36 |
37 | public static final String TSQL_CG_PATH = "sonar.sql.tsql.cg.path";
38 |
39 | public static final String TSQL_SQLCOVER_PATH = "sonar.sql.tsql.sqlcover.report";
40 |
41 | public static final String TSQL_SQLCOVER_PATH_DEFAULT = "Coverage.opencoverxml";
42 |
43 | public static final String SQL_SQLCHECK_ENGINEID = "sqlcheck";
44 |
45 | public static final String SQL_SQLCHECK_PATH = "sonar.sql.sqlcheck.path";
46 |
47 | public static final String SQL_SQLCHECK_PATH_DEFAULT = "/usr/bin/sqlcheck";
48 |
49 | public static final String PLUGIN_SQL_SCA_MAX_FILE_SIZE = "sonar.sql.sca.maxfilesize";
50 |
51 | public static final long PLUGIN_SQL_SCA_MAX_FILE_SIZE_DEFAULT = 1024 * 1024 * 2l;
52 | }
53 |
--------------------------------------------------------------------------------
/src/sonar-sql-plugin/src/test/java/org/sonar/plugins/sql/sensors/CGIssuesSensorTest.java:
--------------------------------------------------------------------------------
1 | package org.sonar.plugins.sql.sensors;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.nio.file.Files;
6 | import org.apache.commons.io.FileUtils;
7 | import org.junit.Assert;
8 | import org.junit.Assume;
9 | import org.junit.Rule;
10 | import org.junit.Test;
11 | import org.junit.rules.TemporaryFolder;
12 | import org.sonar.api.batch.fs.internal.DefaultInputFile;
13 | import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
14 | import org.sonar.api.batch.sensor.internal.SensorContextTester;
15 | import org.sonar.api.impl.utils.JUnitTempFolder;
16 | import org.sonar.plugins.sql.Constants;
17 |
18 | public class CGIssuesSensorTest {
19 |
20 | @Rule public TemporaryFolder folder = new TemporaryFolder();
21 |
22 | @org.junit.Rule public JUnitTempFolder temp = new org.sonar.api.impl.utils.JUnitTempFolder();
23 |
24 | @Test
25 | public void testExecute() throws IOException {
26 |
27 | Assume.assumeTrue("Tool exists", new File(Constants.TSQL_CG_PATH_DEFAULT).exists());
28 |
29 | SensorContextTester ctxTester = SensorContextTester.create(folder.getRoot());
30 | ctxTester.fileSystem().setWorkDir(folder.getRoot().toPath());
31 |
32 | File baseFile = folder.newFile("sample.sql");
33 |
34 | FileUtils.copyURLToFile(getClass().getResource("/tsql/sample1.sql"), baseFile);
35 | String contents = new String(Files.readAllBytes(baseFile.toPath()));
36 |
37 | DefaultInputFile ti =
38 | new TestInputFileBuilder("test", folder.getRoot(), baseFile)
39 | .initMetadata(contents)
40 | .setLanguage(Constants.languageKey)
41 | .setContents(contents)
42 | .setProjectBaseDir(folder.getRoot().toPath())
43 | .build();
44 | ctxTester.fileSystem().add(ti);
45 |
46 | CGIssuesSensor s = new CGIssuesSensor(temp);
47 | s.execute(ctxTester);
48 |
49 | Assert.assertEquals(1, ctxTester.allExternalIssues().size());
50 | Assert.assertEquals(0, ctxTester.allIssues().size());
51 | Assert.assertEquals(1, ctxTester.allAdHocRules().size());
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/sonar-sql-plugin/src/test/java/org/sonar/plugins/sql/sensors/SQLCheckSensorTest.java:
--------------------------------------------------------------------------------
1 | package org.sonar.plugins.sql.sensors;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.nio.file.Files;
6 | import org.apache.commons.io.FileUtils;
7 | import org.junit.Assert;
8 | import org.junit.Assume;
9 | import org.junit.Rule;
10 | import org.junit.Test;
11 | import org.junit.rules.TemporaryFolder;
12 | import org.sonar.api.batch.fs.internal.DefaultInputFile;
13 | import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
14 | import org.sonar.api.batch.sensor.internal.SensorContextTester;
15 | import org.sonar.api.impl.utils.JUnitTempFolder;
16 | import org.sonar.plugins.sql.Constants;
17 |
18 | public class SQLCheckSensorTest {
19 |
20 | @Rule public TemporaryFolder folder = new TemporaryFolder();
21 |
22 | @org.junit.Rule public JUnitTempFolder temp = new org.sonar.api.impl.utils.JUnitTempFolder();
23 |
24 | @Test
25 | public void testExecute() throws IOException {
26 |
27 | Assume.assumeTrue("Tool exists", new File(Constants.SQL_SQLCHECK_PATH_DEFAULT).exists());
28 | SensorContextTester ctxTester = SensorContextTester.create(folder.getRoot());
29 | ctxTester.fileSystem().setWorkDir(folder.getRoot().toPath());
30 |
31 | File baseFile = folder.newFile("sample2.sql");
32 |
33 | FileUtils.copyURLToFile(getClass().getResource("/tsql/sample1.sql"), baseFile);
34 | String contents = new String(Files.readAllBytes(baseFile.toPath()));
35 |
36 | DefaultInputFile ti =
37 | new TestInputFileBuilder("test", folder.getRoot(), baseFile)
38 | .initMetadata(contents)
39 | .setLanguage(Constants.languageKey)
40 | .setContents(contents)
41 | .setProjectBaseDir(folder.getRoot().toPath())
42 | .build();
43 | ctxTester.fileSystem().add(ti);
44 |
45 | SqlCheckSensor s = new SqlCheckSensor(temp);
46 | s.execute(ctxTester);
47 |
48 | Assert.assertEquals(3, ctxTester.allExternalIssues().size());
49 | Assert.assertEquals(0, ctxTester.allIssues().size());
50 | Assert.assertEquals(3, ctxTester.allAdHocRules().size());
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/external/pom.xml:
--------------------------------------------------------------------------------
1 | The following schema fragment specifies the expected content contained within this class. 22 | * 23 | *
24 | * <complexType>
25 | * <complexContent>
26 | * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
27 | * <sequence>
28 | * <element ref="{}textItem" maxOccurs="unbounded" minOccurs="0"/>
29 | * </sequence>
30 | * </restriction>
31 | * </complexContent>
32 | * </complexType>
33 | *
34 | */
35 | @XmlAccessorType(XmlAccessType.FIELD)
36 | @XmlType(
37 | name = "",
38 | propOrder = {"textItem"})
39 | @XmlRootElement(name = "names")
40 | public class Names {
41 |
42 | protected ListThis accessor method returns a reference to the live list, not a snapshot. Therefore any
48 | * modification you make to the returned list will be present inside the JAXB object. This is
49 | * why there is not a set method for the textItem property.
50 | *
51 | *
For example, to add a new item, do as follows: 52 | * 53 | *
54 | * getTextItem().add(newItem); 55 | *56 | * 57 | *
Objects of the following type(s) are allowed in the list {@link String }
58 | */
59 | public List The following schema fragment specifies the expected content contained within this class.
22 | *
23 | * This accessor method returns a reference to the live list, not a snapshot. Therefore any
48 | * modification you make to the returned list will be present inside the JAXB object. This is
49 | * why there is not a For example, to add a new item, do as follows:
52 | *
53 | * Objects of the following type(s) are allowed in the list {@link String }
58 | */
59 | public List The following schema fragment specifies the expected content contained within this class.
20 | *
21 | *
22 | *
23 | * The default implementation returns the result of calling
19 | * {@link #visitChildren} on {@code ctx}. The default implementation returns the result of calling
26 | * {@link #visitChildren} on {@code ctx}. The default implementation returns the result of calling
33 | * {@link #visitChildren} on {@code ctx}. The default implementation returns the result of calling
40 | * {@link #visitChildren} on {@code ctx}. The default implementation returns the result of calling
47 | * {@link #visitChildren} on {@code ctx}. The default implementation returns the result of calling
54 | * {@link #visitChildren} on {@code ctx}. The following schema fragment specifies the expected content contained within this class.
20 | *
21 | *
22 | *
23 | * The following schema fragment specifies the expected content contained within this class.
22 | *
23 | * This accessor method returns a reference to the live list, not a snapshot. Therefore any
48 | * modification you make to the returned list will be present inside the JAXB object. This is
49 | * why there is not a For example, to add a new item, do as follows:
52 | *
53 | * Objects of the following type(s) are allowed in the list {@link String }
58 | */
59 | public List The following schema fragment specifies the expected content contained within this class.
22 | *
23 | * This accessor method returns a reference to the live list, not a snapshot. Therefore any
48 | * modification you make to the returned list will be present inside the JAXB object. This is
49 | * why there is not a For example, to add a new item, do as follows:
52 | *
53 | * Objects of the following type(s) are allowed in the list {@link String }
58 | */
59 | public List The following schema fragment specifies the expected content contained within this class.
22 | *
23 | * This accessor method returns a reference to the live list, not a snapshot. Therefore any
48 | * modification you make to the returned list will be present inside the JAXB object. This is
49 | * why there is not a For example, to add a new item, do as follows:
52 | *
53 | * Objects of the following type(s) are allowed in the list {@link RuleImplementation }
58 | */
59 | public List The following schema fragment specifies the expected content contained within this class.
22 | *
23 | * This accessor method returns a reference to the live list, not a snapshot. Therefore any
48 | * modification you make to the returned list will be present inside the JAXB object. This is
49 | * why there is not a For example, to add a new item, do as follows:
52 | *
53 | * Objects of the following type(s) are allowed in the list {@link RuleImplementation }
58 | */
59 | public List The following schema fragment specifies the expected content contained within this class.
22 | *
23 | * This accessor method returns a reference to the live list, not a snapshot. Therefore any
48 | * modification you make to the returned list will be present inside the JAXB object. This is
49 | * why there is not a For example, to add a new item, do as follows:
52 | *
53 | * Objects of the following type(s) are allowed in the list {@link RuleImplementation }
58 | */
59 | public List The following schema fragment specifies the expected content contained within this class.
22 | *
23 | * This accessor method returns a reference to the live list, not a snapshot. Therefore any
48 | * modification you make to the returned list will be present inside the JAXB object. This is
49 | * why there is not a For example, to add a new item, do as follows:
52 | *
53 | * Objects of the following type(s) are allowed in the list {@link RuleImplementation }
58 | */
59 | public List The following schema fragment specifies the expected content contained within this class.
20 | *
21 | *
22 | *
23 | *
24 | * <complexType>
25 | * <complexContent>
26 | * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
27 | * <sequence>
28 | * <element ref="{}textItem" maxOccurs="unbounded" minOccurs="0"/>
29 | * </sequence>
30 | * </restriction>
31 | * </complexContent>
32 | * </complexType>
33 | *
34 | */
35 | @XmlAccessorType(XmlAccessType.FIELD)
36 | @XmlType(
37 | name = "",
38 | propOrder = {"textItem"})
39 | @XmlRootElement(name = "textToFind")
40 | public class TextToFind {
41 |
42 | protected Listset method for the textItem property.
50 | *
51 | *
54 | * getTextItem().add(newItem);
55 | *
56 | *
57 | *
24 | * <simpleType name="ruleDistanceIndexMatchType">
25 | * <restriction base="{http://www.w3.org/2001/XMLSchema}string">
26 | * <enumeration value="Default"/>
27 | * <enumeration value="More"/>
28 | * <enumeration value="Less"/>
29 | * <enumeration value="Equals"/>
30 | * </restriction>
31 | * </simpleType>
32 | *
33 | */
34 | @XmlType(name = "ruleDistanceIndexMatchType")
35 | @XmlEnum
36 | public enum RuleDistanceIndexMatchType {
37 | @XmlEnumValue("Default")
38 | DEFAULT("Default"),
39 | @XmlEnumValue("More")
40 | MORE("More"),
41 | @XmlEnumValue("Less")
42 | LESS("Less"),
43 | @XmlEnumValue("BeforeOrAfter")
44 | BEFOREORAFTER("BeforeOrAfter"),
45 | @XmlEnumValue("Equals")
46 | EQUALS("Equals");
47 | private final String value;
48 |
49 | RuleDistanceIndexMatchType(String v) {
50 | value = v;
51 | }
52 |
53 | public String value() {
54 | return value;
55 | }
56 |
57 | public static RuleDistanceIndexMatchType fromValue(String v) {
58 | if (StringUtils.isBlank(v)) {
59 | return RuleDistanceIndexMatchType.DEFAULT;
60 | }
61 |
62 | for (RuleDistanceIndexMatchType c : RuleDistanceIndexMatchType.values()) {
63 | if (c.value.equalsIgnoreCase(v) || c.name().equalsIgnoreCase(v)) {
64 | return c;
65 | }
66 | }
67 | throw new IllegalArgumentException(v);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/sonar-sql-plugin/src/test/resources/external/rule1.customRules:
--------------------------------------------------------------------------------
1 |
2 |
24 | * <simpleType name="ruleMatchType">
25 | * <restriction base="{http://www.w3.org/2001/XMLSchema}string">
26 | * <enumeration value="Default"/>
27 | * <enumeration value="Full"/>
28 | * <enumeration value="TextOnly"/>
29 | * <enumeration value="TextAndClass"/>
30 | * <enumeration value="ClassOnly"/>
31 | * <enumeration value="Strict"/>
32 | * </restriction>
33 | * </simpleType>
34 | *
35 | */
36 | @XmlType(name = "ruleMatchType")
37 | @XmlEnum
38 | public enum RuleMatchType {
39 | @XmlEnumValue("Default")
40 | DEFAULT("Default"),
41 | @XmlEnumValue("Full")
42 | FULL("Full"),
43 | @XmlEnumValue("TextOnly")
44 | TEXT_ONLY("TextOnly"),
45 | @XmlEnumValue("TextAndClass")
46 | TEXT_AND_CLASS("TextAndClass"),
47 | @XmlEnumValue("ClassOnly")
48 | CLASS_ONLY("ClassOnly"),
49 | @XmlEnumValue("Strict")
50 | STRICT("Strict");
51 | private final String value;
52 |
53 | RuleMatchType(String v) {
54 | value = v;
55 | }
56 |
57 | public String value() {
58 | return value;
59 | }
60 |
61 | public static RuleMatchType fromValue(String v) {
62 | if (StringUtils.isBlank(v)) {
63 | return RuleMatchType.DEFAULT;
64 | }
65 | for (RuleMatchType c : RuleMatchType.values()) {
66 | if (c.value.equalsIgnoreCase(v) || c.name().equalsIgnoreCase(v)) {
67 | return c;
68 | }
69 | }
70 | throw new IllegalArgumentException(v);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/sonar-sql-plugin/src/test/java/org/antlr/sql/tools/ClassesLister.java:
--------------------------------------------------------------------------------
1 | package org.antlr.sql.tools;
2 |
3 | import com.google.common.reflect.ClassPath;
4 | import java.io.File;
5 | import java.io.IOException;
6 | import java.util.Arrays;
7 | import java.util.List;
8 | import java.util.TreeSet;
9 | import org.apache.commons.io.FileUtils;
10 |
11 | public class ClassesLister {
12 |
13 | private static class ListData {
14 | public String dialect;
15 | public String packageName;
16 |
17 | public ListData(String dialect, String packageName) {
18 | this.dialect = dialect;
19 | this.packageName = packageName;
20 | }
21 | }
22 |
23 | public static void main(String[] args) throws IOException {
24 |
25 | List
24 | * <complexType>
25 | * <complexContent>
26 | * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
27 | * <sequence>
28 | * <element ref="{}ruleCodeExample" maxOccurs="unbounded" minOccurs="0"/>
29 | * </sequence>
30 | * </restriction>
31 | * </complexContent>
32 | * </complexType>
33 | *
34 | */
35 | @XmlAccessorType(XmlAccessType.FIELD)
36 | @XmlType(
37 | name = "",
38 | propOrder = {"ruleCodeExample"})
39 | @XmlRootElement(name = "compliantRulesCodeExamples")
40 | public class CompliantRulesCodeExamples {
41 |
42 | protected Listset method for the ruleCodeExample property.
50 | *
51 | *
54 | * getRuleCodeExample().add(newItem);
55 | *
56 | *
57 | *
24 | * <complexType>
25 | * <complexContent>
26 | * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
27 | * <sequence>
28 | * <element ref="{}ruleCodeExample" maxOccurs="unbounded" minOccurs="0"/>
29 | * </sequence>
30 | * </restriction>
31 | * </complexContent>
32 | * </complexType>
33 | *
34 | */
35 | @XmlAccessorType(XmlAccessType.FIELD)
36 | @XmlType(
37 | name = "",
38 | propOrder = {"ruleCodeExample"})
39 | @XmlRootElement(name = "violatingRulesCodeExamples")
40 | public class ViolatingRulesCodeExamples {
41 |
42 | protected Listset method for the ruleCodeExample property.
50 | *
51 | *
54 | * getRuleCodeExample().add(newItem);
55 | *
56 | *
57 | *
24 | * <complexType>
25 | * <complexContent>
26 | * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
27 | * <sequence>
28 | * <element ref="{}ruleImplementation" maxOccurs="unbounded" minOccurs="0"/>
29 | * </sequence>
30 | * </restriction>
31 | * </complexContent>
32 | * </complexType>
33 | *
34 | */
35 | @XmlAccessorType(XmlAccessType.FIELD)
36 | @XmlType(
37 | name = "",
38 | propOrder = {"ruleImplementation"})
39 | @XmlRootElement(name = "usesRules")
40 | public class UsesRules {
41 |
42 | protected Listset method for the ruleImplementation property.
50 | *
51 | *
54 | * getRuleImplementation().add(newItem);
55 | *
56 | *
57 | *
24 | * <complexType>
25 | * <complexContent>
26 | * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
27 | * <sequence>
28 | * <element ref="{}ruleImplementation" maxOccurs="unbounded" minOccurs="0"/>
29 | * </sequence>
30 | * </restriction>
31 | * </complexContent>
32 | * </complexType>
33 | *
34 | */
35 | @XmlAccessorType(XmlAccessType.FIELD)
36 | @XmlType(
37 | name = "",
38 | propOrder = {"ruleImplementation"})
39 | @XmlRootElement(name = "parentRules")
40 | public class ParentRules {
41 |
42 | protected Listset method for the ruleImplementation property.
50 | *
51 | *
54 | * getRuleImplementation().add(newItem);
55 | *
56 | *
57 | *
24 | * <complexType>
25 | * <complexContent>
26 | * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
27 | * <sequence>
28 | * <element ref="{}ruleImplementation" maxOccurs="unbounded" minOccurs="0"/>
29 | * </sequence>
30 | * </restriction>
31 | * </complexContent>
32 | * </complexType>
33 | *
34 | */
35 | @XmlAccessorType(XmlAccessType.FIELD)
36 | @XmlType(
37 | name = "",
38 | propOrder = {"ruleImplementation"})
39 | @XmlRootElement(name = "childrenRules")
40 | public class ChildrenRules {
41 |
42 | protected Listset method for the ruleImplementation property.
50 | *
51 | *
54 | * getRuleImplementation().add(newItem);
55 | *
56 | *
57 | *
24 | * <complexType>
25 | * <complexContent>
26 | * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
27 | * <sequence>
28 | * <element ref="{}ruleImplementation" maxOccurs="unbounded" minOccurs="0"/>
29 | * </sequence>
30 | * </restriction>
31 | * </complexContent>
32 | * </complexType>
33 | *
34 | */
35 | @XmlAccessorType(XmlAccessType.FIELD)
36 | @XmlType(
37 | name = "",
38 | propOrder = {"ruleImplementation"})
39 | @XmlRootElement(name = "siblingsRules")
40 | public class SiblingsRules {
41 |
42 | protected Listset method for the ruleImplementation property.
50 | *
51 | *
54 | * getRuleImplementation().add(newItem);
55 | *
56 | *
57 | *
24 | * <simpleType name="ruleResultType">
25 | * <restriction base="{http://www.w3.org/2001/XMLSchema}string">
26 | * <enumeration value="Default"/>
27 | * <enumeration value="FailIfFound"/>
28 | * <enumeration value="FailIfNotFound"/>
29 | * <enumeration value="FailIfLessFound"/>
30 | * <enumeration value="FailIfMoreFound"/>
31 | * <enumeration value="SkipIfFound"/>
32 | * <enumeration value="SkipIfNotFound"/>
33 | * </restriction>
34 | * </simpleType>
35 | *
36 | */
37 | @XmlType(name = "ruleResultType")
38 | @XmlEnum
39 | public enum RuleResultType {
40 | @XmlEnumValue("Default")
41 | DEFAULT("Default"),
42 | @XmlEnumValue("FailIfFound")
43 | FAIL_IF_FOUND("FailIfFound"),
44 | @XmlEnumValue("FailIfNotFound")
45 | FAIL_IF_NOT_FOUND("FailIfNotFound"),
46 | @XmlEnumValue("FailIfLessFound")
47 | FAIL_IF_LESS_FOUND("FailIfLessFound"),
48 | @XmlEnumValue("FailIfMoreFound")
49 | FAIL_IF_MORE_FOUND("FailIfMoreFound"),
50 | @XmlEnumValue("SkipIfFound")
51 | SKIP_IF_FOUND("SkipIfFound"),
52 |
53 | @XmlEnumValue("SkipIfLessFound")
54 | SKIP_IF_LESS_FOUND("SkipIfLessFound"),
55 | @XmlEnumValue("SkipIfMoreFound")
56 | SKIP_IF_MORE_FOUND("FailIfMoreFound"),
57 | @XmlEnumValue("SkipIfNotFound")
58 | SKIP_IF_NOT_FOUND("SkipIfNotFound");
59 | private final String value;
60 |
61 | RuleResultType(String v) {
62 | value = v;
63 | }
64 |
65 | public String value() {
66 | return value;
67 | }
68 |
69 | public static RuleResultType fromValue(String v) {
70 | if (StringUtils.isBlank(v)) {
71 | return RuleResultType.DEFAULT;
72 | }
73 |
74 | for (RuleResultType c : RuleResultType.values()) {
75 | if (c.value.equalsIgnoreCase(v) || c.name().equalsIgnoreCase(v)) {
76 | return c;
77 | }
78 | }
79 | throw new IllegalArgumentException(v);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/sonar-sql-plugin/src/main/java/org/sonar/plugins/sql/fillers/CommentIssuesFiller.java:
--------------------------------------------------------------------------------
1 | package org.sonar.plugins.sql.fillers;
2 |
3 | import java.io.IOException;
4 | import java.util.List;
5 | import org.antlr.sql.dialects.comments.CommentsGrammarLexer;
6 | import org.antlr.sql.dialects.comments.CommentsGrammarParser;
7 | import org.antlr.sql.models.AntlrContext;
8 | import org.antlr.sql.sca.IssuesProvider;
9 | import org.antlr.v4.runtime.CharStream;
10 | import org.antlr.v4.runtime.CharStreams;
11 | import org.antlr.v4.runtime.CommonTokenStream;
12 | import org.antlr.v4.runtime.Lexer;
13 | import org.antlr.v4.runtime.tree.ParseTree;
14 | import org.sonar.api.batch.fs.InputFile;
15 | import org.sonar.api.batch.sensor.SensorContext;
16 | import org.sonar.api.utils.log.Logger;
17 | import org.sonar.api.utils.log.Loggers;
18 | import org.sonar.plugins.sql.CaseChangingCharStream;
19 | import org.sonar.plugins.sql.issues.RuleToCheck;
20 | import org.sonar.plugins.sql.issues.SqlIssuesList;
21 | import org.sonar.plugins.sql.models.rules.SqlRules;
22 | import org.sonar.plugins.sql.sensors.BaseSensor;
23 |
24 | public class CommentIssuesFiller extends BaseSensor implements Filler {
25 | private static final Logger LOGGER = Loggers.get(CommentIssuesFiller.class);
26 | private final IssuesProvider issuesProvider = new IssuesProvider();
27 |
28 | @Override
29 | public void fill(InputFile file, SensorContext context, AntlrContext antlrContext) {
30 |
31 | try {
32 |
33 | SqlIssuesList sqlIssuesList = getIssues(antlrContext);
34 |
35 | try {
36 | addIssues(context, sqlIssuesList, file);
37 | } catch (IOException e) {
38 | e.printStackTrace();
39 | }
40 |
41 | } catch (IOException e1) {
42 | LOGGER.warn("Unexpected error adding issues", e1);
43 | }
44 | }
45 |
46 | public SqlIssuesList getIssues(AntlrContext antlrContext) throws IOException {
47 | ParseTree root = getRoot(antlrContext);
48 |
49 | List