├── .gitignore ├── .gitmodules ├── .travis.yml ├── LICENSE ├── README.md ├── examples ├── .gitignore ├── example1-rules │ ├── Example.sln │ ├── Example │ │ ├── Example.sqlproj │ │ ├── TestTable.sql │ │ └── sp_Get.sql │ ├── README.md │ ├── customRules │ │ └── myExampleRepo.customRules │ ├── sonar-project.properties │ └── sqlcodeguardsettings.xml ├── example2-coverage │ ├── README.md │ ├── build │ │ └── Coverage.opencoverxml │ ├── runSqlCover.ps1 │ ├── sonar-project.properties │ └── src │ │ ├── Accelerator │ │ └── IsExperimentReady.sql │ │ ├── AlertParticleDiscovered.sql │ │ ├── GetStatusMessage.sql │ │ └── SendHiggsBosonDiscoveryEmail.sql ├── example3-full │ ├── 00-installTools.ps1 │ ├── 01-executeDBChanges.ps1 │ ├── 02-runSonar.ps1 │ ├── README.md │ ├── imgs │ │ └── sonarDashboard.png │ └── src │ │ └── ExampleDatabase │ │ ├── ExampleDatabase.sln │ │ └── ExampleDatabase │ │ ├── .gitignore │ │ ├── Billing.sql │ │ ├── Billing │ │ ├── CustomerDiscounts.sql │ │ ├── Customers.sql │ │ ├── IsCustomerEligibleForDiscount.sql │ │ └── Orders.sql │ │ ├── BillingTests.sql │ │ ├── BillingTests │ │ ├── test that customer with more than 3 orders and total over 2000 can discount.sql │ │ └── test that not existing customer can not get discount.sql │ │ └── ExampleDatabase.sqlproj └── example4-adhoc │ ├── Example.sln │ ├── Example │ ├── Example.sqlproj │ ├── TestTable.sql │ └── sp_Get.sql │ ├── README.md │ ├── customRules │ └── myExampleRepo.customRules │ ├── sonar-project.properties │ └── sqlcodeguardsettings.xml ├── scripts ├── index.js └── package.json └── sonar-tsql-plugin ├── .classpath ├── .gitignore ├── .project ├── pom.xml └── src ├── main ├── antlr4 │ └── org │ │ └── sonar │ │ └── plugins │ │ └── tsql │ │ └── antlr4 │ │ └── tsql.g4 ├── java │ └── org │ │ ├── antlr │ │ └── tsql │ │ │ ├── TSqlLexer.java │ │ │ ├── TSqlLexer.tokens │ │ │ ├── TSqlParser.java │ │ │ ├── TSqlParser.tokens │ │ │ ├── TSqlParserBaseListener.java │ │ │ ├── TSqlParserBaseVisitor.java │ │ │ ├── TSqlParserListener.java │ │ │ └── TSqlParserVisitor.java │ │ ├── opencover │ │ ├── Class.java │ │ ├── Classes.java │ │ ├── CoverageSession.java │ │ ├── File.java │ │ ├── FileRef.java │ │ ├── Files.java │ │ ├── Method.java │ │ ├── Methods.java │ │ ├── Module.java │ │ ├── Modules.java │ │ ├── ObjectFactory.java │ │ ├── SequencePoint.java │ │ ├── SequencePoints.java │ │ └── Summary.java │ │ └── sonar │ │ └── plugins │ │ └── tsql │ │ ├── Constants.java │ │ ├── TSQLPlugin.java │ │ ├── antlr │ │ ├── AntlrContext.java │ │ ├── CandidateNode.java │ │ ├── CandidateRule.java │ │ ├── CaseChangingCharStream.java │ │ ├── IParsedNode.java │ │ ├── PluginHelper.java │ │ ├── issues │ │ │ ├── CustomIssuesProvider.java │ │ │ ├── FoundViolationsAnalyzer.java │ │ │ └── NodesMatchingRulesProvider.java │ │ ├── lines │ │ │ ├── DefaultLinesProvider.java │ │ │ └── ILinesProvider.java │ │ ├── nodes │ │ │ ├── INodesProvider.java │ │ │ ├── NodeUsesProvider.java │ │ │ ├── ParsedNode.java │ │ │ └── matchers │ │ │ │ ├── ABaseMatcher.java │ │ │ │ ├── ClassNameMatcher.java │ │ │ │ ├── DistanceMatcher.java │ │ │ │ ├── IMatcher.java │ │ │ │ ├── IParentMatcher.java │ │ │ │ ├── IndexMatcher.java │ │ │ │ ├── NodeNameAndOrClassMatcher.java │ │ │ │ ├── ParentsMatcher.java │ │ │ │ ├── RulesMatcher.java │ │ │ │ ├── SameTextMatcher.java │ │ │ │ └── TextNameMatcher.java │ │ └── visitors │ │ │ ├── AntlrHighlighter.java │ │ │ ├── CComplexityVisitor.java │ │ │ ├── ComplexityVisitor.java │ │ │ ├── CustomRulesVisitor.java │ │ │ ├── CustomTreeVisitor.java │ │ │ ├── IParseTreeItemVisitor.java │ │ │ └── SourceLinesMeasuresFiller.java │ │ ├── checks │ │ ├── CustomAllChecksProvider.java │ │ ├── CustomPluginChecks.java │ │ ├── CustomUserChecksProvider.java │ │ └── custom │ │ │ ├── ChildrenRules.java │ │ │ ├── CompliantRulesCodeExamples.java │ │ │ ├── Names.java │ │ │ ├── ObjectFactory.java │ │ │ ├── ParentRules.java │ │ │ ├── Rule.java │ │ │ ├── RuleDistanceIndexMatchType.java │ │ │ ├── RuleImplementation.java │ │ │ ├── RuleMatchType.java │ │ │ ├── RuleMode.java │ │ │ ├── RuleResultType.java │ │ │ ├── SiblingsRules.java │ │ │ ├── SqlRules.java │ │ │ ├── TextCheckType.java │ │ │ ├── TextToFind.java │ │ │ ├── UsesRules.java │ │ │ └── ViolatingRulesCodeExamples.java │ │ ├── coverage │ │ ├── CoveredLinesReport.java │ │ ├── FileNamesMatcher.java │ │ ├── ICoveragProvider.java │ │ ├── NameNormalizer.java │ │ └── SqlCoverCoverageProvider.java │ │ ├── languages │ │ ├── TSQLLanguage.java │ │ ├── TSQLQualityProfile.java │ │ ├── TSQLRules.java │ │ └── keywords │ │ │ ├── IKeywordsProvider.java │ │ │ └── KeywordsProvider.java │ │ ├── lines │ │ ├── SourceLine.java │ │ └── SourceLinesProvider.java │ │ ├── predicates │ │ └── AbsolutePathCaseInsensitivePredicate.java │ │ ├── rules │ │ ├── definitions │ │ │ ├── BaseRulesDefinition.java │ │ │ ├── CodeGuardRulesDefinition.java │ │ │ ├── CustomPluginChecksRulesDefinition.java │ │ │ ├── CustomUserChecksRulesDefinition.java │ │ │ └── MsRulesDefinition.java │ │ ├── files │ │ │ ├── BaseReportsProvider.java │ │ │ ├── CodeGuardExecutingReportsProvider.java │ │ │ ├── FilesProvider.java │ │ │ └── IReportsProvider.java │ │ ├── issues │ │ │ ├── CodeGuardIssues.java │ │ │ ├── CodeGuardIssuesProvider.java │ │ │ ├── DefaultIssuesFiller.java │ │ │ ├── IIssuesFiller.java │ │ │ ├── IIssuesProvider.java │ │ │ ├── MsIssues.java │ │ │ ├── MsIssuesProvider.java │ │ │ └── TsqlIssue.java │ │ └── parsers │ │ │ ├── CodeGuardIssuesParser.java │ │ │ ├── IIssuesParser.java │ │ │ └── MsIssuesParser.java │ │ └── sensors │ │ ├── BaseTsqlExternalSensor.java │ │ ├── BaseTsqlSensor.java │ │ ├── CodeGuardIssuesLoaderSensor.java │ │ ├── CoverageSensor.java │ │ ├── CustomChecksSensor.java │ │ └── MsIssuesLoaderSensor.java └── resources │ ├── config │ └── sqlcodeguardsettings.xml │ ├── rules │ ├── cgsql-rules.xml │ └── vssql-rules.xml │ ├── schemas │ ├── codeGuard.xsd │ ├── coverage.xsd │ ├── customRules.xsd │ ├── sqlRules.xsd │ └── visualStudio.xsd │ ├── tsql.keywords │ └── tsql.odbc.keywords └── test ├── java └── org │ └── sonar │ └── plugins │ └── tsql │ ├── antlr │ ├── AntlrContextTest.java │ ├── CustomChecksTest.java │ ├── CustomRulesVerificationTest.java │ ├── issues │ │ └── FoundViolationsAnalyzerTest.java │ ├── lines │ │ └── DefaultLinesProviderTest.java │ └── nodes │ │ ├── NodeUsesProviderTest.java │ │ ├── NodesMatchingRulesProviderTest.java │ │ ├── ParsedNodeTest.java │ │ └── matchers │ │ ├── DistanceMatcherTest.java │ │ ├── IndexMatcherTest.java │ │ └── RulesMatcherTest.java │ ├── coverage │ └── FileNamesMatcherTest.java │ ├── helpers │ ├── AntlrUtils.java │ ├── AntrlResult.java │ ├── ClassesLister.java │ ├── CustomRulesPrinter.java │ ├── CustomSqlCodePrinter.java │ ├── RulesHelperTool.java │ └── TestNode.java │ ├── languages │ ├── TSQLLanguageTest.java │ └── keywords │ │ └── KeywordsProviderTest.java │ ├── lines │ └── SourceLinesProviderTest.java │ ├── rules │ ├── BaseReportsProviderTest.java │ ├── CgSqlIssuesParserTest.java │ ├── VsSqlIssuesParserTest.java │ ├── definitions │ │ └── CustomUserChecksProviderTest.java │ └── files │ │ └── FilesProviderTest.java │ └── sensors │ ├── BaseTsqlSensorTest.java │ ├── CoverageSensorTest.java │ ├── CustomChecksSensorTest.java │ └── antlr4 │ ├── CComplexityVisitorTest.java │ └── ComplexityVisitorTest.java └── resources ├── cgSample.xml ├── coverage ├── Coverage.opencoverxml ├── TestCode.sql ├── [Accelerator].[AlertParticleDiscovered] ├── [Accelerator].[GetStatusMessage] ├── [Accelerator].[IsExperimentReady] └── [Accelerator].[SendHiggsBosonDiscoveryEmail] ├── customRulesSample.xml ├── customRulesSample2.xml ├── finalCusomRulesSample.xml ├── testFiles ├── TestTable.sql ├── cursorFlow.sql ├── cursorFlow2.sql ├── scriptExample.sql ├── scriptExample2.sql ├── scriptExample3.sql └── sp_Get.sql └── vsSample.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | .settings 14 | node_modules 15 | scripts/rules/*.html 16 | rules.xml 17 | scripts/package-lock.json 18 | examples/**/bin/Debug/** 19 | examples/**/obj/Debug/** 20 | examples/**/.scannerwork/** -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "grammars"] 2 | path = grammars 3 | url = https://github.com/antlr/grammars-v4.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | sudo: false 3 | install: true 4 | 5 | jdk: 6 | - oraclejdk8 7 | 8 | script: 9 | - cd sonar-tsql-plugin 10 | - ./mvnw clean install 11 | 12 | cache: 13 | directories: 14 | - $HOME/.m2 15 | 16 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | .settings 14 | node_modules 15 | scripts/rules/*.html 16 | rules.xml 17 | scripts/package-lock.json 18 | -------------------------------------------------------------------------------- /examples/example1-rules/Example.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "Example", "Example\Example.sqlproj", "{1491DCE3-0018-487C-9B9B-F7EEA6C863F8}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {1491DCE3-0018-487C-9B9B-F7EEA6C863F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {1491DCE3-0018-487C-9B9B-F7EEA6C863F8}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {1491DCE3-0018-487C-9B9B-F7EEA6C863F8}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 17 | {1491DCE3-0018-487C-9B9B-F7EEA6C863F8}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {1491DCE3-0018-487C-9B9B-F7EEA6C863F8}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {1491DCE3-0018-487C-9B9B-F7EEA6C863F8}.Release|Any CPU.Deploy.0 = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | EndGlobal 25 | -------------------------------------------------------------------------------- /examples/example1-rules/Example/TestTable.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [dbo].[TestTable] 2 | ( 3 | [Id] INT NOT NULL PRIMARY KEY, 4 | [Name] NVARCHAR(MAX) NULL 5 | ) 6 | -------------------------------------------------------------------------------- /examples/example1-rules/Example/sp_Get.sql: -------------------------------------------------------------------------------- 1 | CREATE PROCEDURE [dbo].[sp_Get] 2 | @param1 int = 0, 3 | @param2 int 4 | AS 5 | BEGIN 6 | SELECT * FROM TestTable; 7 | EXEC ('SELECT 1'); 8 | insert into dbo.test values (1,2); 9 | 10 | EXECUTE sp_executesql N'select 1'; 11 | 12 | RETURN 0 13 | END 14 | -- kasldjaskjd -------------------------------------------------------------------------------- /examples/example1-rules/README.md: -------------------------------------------------------------------------------- 1 | # Example T-SQL project 2 | In order to get results to sonar server please: 3 | 4 | - (Optional) If needed update path to SQL code guard on sonar server or add **sonar.tsql.cg.path** setting with path in sonar.properties file 5 | - (Optional) Build sample project with setting /p:RunSqlCodeAnalysis=true if not using other means for building: 6 | - msbuild /p:RunSqlCodeAnalysis=true 7 | - (Optional) Update sonar-project.properties file as needed 8 | - Run sonar scanner 9 | 10 | ## Using custom rules ## 11 | - (Optional) Please update file **myExampleRepo.customRules** in *customRules* directory with your custom rules 12 | - Copy **myExampleRepo.customRules** file to SonarQube's server known place, i.e. **C:\\sonar\\rules** folder 13 | - Set on server sonar **sonar.tsql.customrules.paths** setting to **C:\\sonar\\rules\\** or **C:\\sonar\\rules\\myExampleRepo.customRules** 14 | - Restart SonarQube server 15 | - Run sonar scanner -------------------------------------------------------------------------------- /examples/example1-rules/sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectKey=example1.tsql.project 2 | sonar.projectName=Example1: TSQL project 3 | sonar.projectVersion=1.0 4 | sonar.sources=Example 5 | sonar.sourceEncoding=UTF-8 6 | sonar.language=tsql 7 | ## not needed to specify if rules are placed in the same place as on sonar server. Can be relative or absolute path. 8 | sonar.tsql.customrules.paths=./customRules 9 | ## not needed to update if matches server settings 10 | #sonar.tsql.customrules.prefix=.customRules 11 | -------------------------------------------------------------------------------- /examples/example2-coverage/README.md: -------------------------------------------------------------------------------- 1 | # Example project 2 # 2 | This project illustrates plugin's ability to report SQLCover coverage for a sample database taken from [https://tsqlt.org/](https://tsqlt.org/) installation. Coverage report is already saved at **build** folder. When you run sonar-scanner that report will be parsed and reported to Sonarqube. -------------------------------------------------------------------------------- /examples/example2-coverage/build/Coverage.opencoverxml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gretard/sonar-tsql-plugin/aadb5598bbb183c12df997ee9f3e053f962ce0f7/examples/example2-coverage/build/Coverage.opencoverxml -------------------------------------------------------------------------------- /examples/example2-coverage/runSqlCover.ps1: -------------------------------------------------------------------------------- 1 | . .\SQLCover.ps1 2 | $result = Get-CoverTSql ".\SQLCover.dll" "server=.;initial catalog=tSQLt_Example;integrated security=sspi;" "tSQLt_Example" "exec tSQLt.RunAll" 3 | $result 4 | Export-OpenXml $result "$PSScriptRoot\build" -------------------------------------------------------------------------------- /examples/example2-coverage/sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectKey=example2.tsql.project 2 | sonar.projectName=Example2: TSQL project 3 | sonar.projectVersion=1.1 4 | sonar.sources=src 5 | 6 | ##flag if you want to skip coverage reports 7 | ##sonar.tsql.sqlcover.skip=true 8 | 9 | ##By default plugin will try to find Coverage.opencoverxml file in the base dir, however you could specify it if needed to some absolute or reltive path 10 | ##sonar.tsql.sqlcover.report=./build/Coverage.opencoverxml -------------------------------------------------------------------------------- /examples/example2-coverage/src/Accelerator/IsExperimentReady.sql: -------------------------------------------------------------------------------- 1 | 2 | CREATE FUNCTION Accelerator.IsExperimentReady() 3 | RETURNS BIT 4 | AS 5 | BEGIN 6 | DECLARE @NumParticles INT; 7 | 8 | SELECT @NumParticles = COUNT(1) FROM Accelerator.Particle; 9 | 10 | IF @NumParticles > 2 11 | RETURN 1; 12 | 13 | RETURN 0; 14 | END; 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/example2-coverage/src/AlertParticleDiscovered.sql: -------------------------------------------------------------------------------- 1 | 2 | CREATE PROCEDURE Accelerator.AlertParticleDiscovered 3 | @ParticleDiscovered NVARCHAR(MAX) 4 | AS 5 | BEGIN 6 | IF @ParticleDiscovered = 'Higgs Boson' 7 | BEGIN 8 | EXEC Accelerator.SendHiggsBosonDiscoveryEmail 'particle-discovery@new-era-particles.tsqlt.org'; 9 | END; 10 | END; 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/example2-coverage/src/GetStatusMessage.sql: -------------------------------------------------------------------------------- 1 | 2 | CREATE FUNCTION Accelerator.GetStatusMessage() 3 | RETURNS NVARCHAR(MAX) 4 | AS 5 | BEGIN 6 | DECLARE @NumParticles INT; 7 | SELECT @NumParticles = COUNT(1) FROM Accelerator.Particle; 8 | RETURN 'The Accelerator is prepared with ' + CAST(@NumParticles AS NVARCHAR(MAX)) + ' particles.'; 9 | END; 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/example2-coverage/src/SendHiggsBosonDiscoveryEmail.sql: -------------------------------------------------------------------------------- 1 | 2 | CREATE PROCEDURE Accelerator.SendHiggsBosonDiscoveryEmail 3 | @EmailAddress NVARCHAR(MAX) 4 | AS 5 | BEGIN 6 | RAISERROR('Not Implemented - yet',16,10); 7 | END; 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/example3-full/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://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-3.2.0.1227-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/example3-full/01-executeDBChanges.ps1: -------------------------------------------------------------------------------- 1 | Add-Type -AssemblyName System.IO.Compression.FileSystem 2 | function Uzip-File { 3 | param( [string]$ziparchive, [string]$extractpath ) 4 | [System.IO.Compression.ZipFile]::ExtractToDirectory( $ziparchive, $extractpath ) 5 | } 6 | 7 | $baseToolsDir = "$PSScriptRoot\tools"; 8 | $tsqltDir = "$PSScriptRoot\tools\TSQLT" 9 | 10 | 11 | $server = ".\SQLEXPRESS01" 12 | $database = "ExampleDatabase" 13 | 14 | function Setup-TSQLT { 15 | $url = "https://tsqlt.org/download/tsqlt/"; 16 | $output = "$baseToolsDir\tsqlt.zip"; 17 | [Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 18 | $WebClient = New-Object System.Net.WebClient 19 | $WebClient.DownloadFile($url,$output) 20 | Uzip-File -ziparchive $output -extractpath $tsqltDir 21 | } 22 | 23 | Setup-TSQLT 24 | 25 | &sqlcmd -S $server -i "$tsqltDir\SetClrEnabled.sql" 26 | &sqlcmd -S $server -Q "EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'clr strict security', 0; RECONFIGURE;" 27 | &sqlcmd -S $server -Q "CREATE DATABASE $database;" 28 | &sqlcmd -S $server -d $database -i "$tsqltDir\tSQLt.class.sql" 29 | return -------------------------------------------------------------------------------- /examples/example3-full/02-runSonar.ps1: -------------------------------------------------------------------------------- 1 | ## Run tests with SQLCover 2 | $database = "ExampleDatabase" 3 | $server = ".\SQLEXPRESS01" 4 | $cloverDir = "$PSScriptRoot\tools\SQLCover" 5 | $coverageOutputDir = "$PSScriptRoot\build\sqlcoverresults" 6 | 7 | . "$cloverDir\SQLCover.ps1" 8 | $results = Get-CoverTSql "$cloverDir\SQLCover.dll" "server=$server;initial catalog=$database;integrated security=sspi;" "$database " "exec tSQLt.RunAll" 9 | New-Item -ItemType Directory -Force -Path $coverageOutputDir 10 | Export-OpenXml $results "$coverageOutputDir" 11 | 12 | 13 | ## Build and run code analysis 14 | $dbProject = "$PSScriptRoot\src\ExampleDatabase\ExampleDatabase.sln" 15 | $msbuildpath = Resolve-Path "C:\Program Files*\MSBuild\*\Bin\*\MSBuild.exe" | select -ExpandProperty Path -First 1 16 | 17 | 18 | &$msbuildpath "$dbProject" /t:build /p:RunSqlCodeAnalysis=True 19 | 20 | ## Run SQLCodeGuard if needed manually 21 | $sqlCodeGuard = "$PSScriptRoot\tools\SQLCodeGuardCmdLine\SqlCodeGuard30.Cmd.exe" 22 | $sqlCodeGuardResults = "$PSScriptRoot\build\cgtestresults.xml" 23 | $sqlCodeGuardArgs = @( 24 | "-source", 25 | "$PSScriptRoot\src", 26 | "-out", 27 | "$sqlCodeGuardResults", 28 | "/include:all" 29 | ) 30 | &$sqlCodeGuard $sqlCodeGuardArgs 31 | 32 | 33 | 34 | ## Run sonar-scanner 35 | 36 | 37 | $sonarScanner = "$PSScriptRoot\tools\sonar-scanner\sonar-scanner-3.2.0.1227-windows\bin\sonar-scanner.bat" 38 | 39 | $sonarArgs = @( 40 | "-Dsonar.projectKey=tsql.sample.project", 41 | "-Dsonar.projectName=TSQL sample project", 42 | "-Dsonar.projectVersion=1.0", 43 | "-Dsonar.sources=src", 44 | "-Dsonar.host.url=http://localhost:9000" 45 | "-Dsonar.exclusions=**/bin/**/*.*,**/obj/**/*.*,**/*.sqlproj", # skip build files from analysis 46 | 47 | # it is possible to specify absolute path to the SQLCover report or directory where file matching *Coverage.opencoverxml resides, by default plugin will try to find it in the base directory's subdirectories 48 | "-Dsonar.tsql.sqlcover.report=$coverageOutputDir\Coverage.opencoverxml", 49 | 50 | # it is possible to either specify path to sqlcodeguard executable and plugin will try to run it or you can specify actual path to report's xml 51 | # or directory where file matching *cgresults.xml resides by setting sonar.tsql.cg.report property 52 | "-Dsonar.tsql.cg.path=$sqlCodeGuard" 53 | #"-Dsonar.tsql.cg.report=$sqlCodeGuardResults", 54 | 55 | # it is possible to specify absolute path to the MSBuild code analysis report or directory where file matching *StaticCodeAnalysis.Results.xml resides, by default plugin will try to find it in the base directory's subdirectories 56 | #"-Dsonar.tsql.ms.report=$PSScriptRoot\src\ExampleDatabase\ExampleDatabase\bin\Debug" 57 | 58 | ); 59 | &$sonarScanner $sonarArgs -------------------------------------------------------------------------------- /examples/example3-full/README.md: -------------------------------------------------------------------------------- 1 | # TSQL project example # 2 | This folder contains example TSQL project and scripts allowing to setup required tools and illustrating usage of sonar-scanner with TSQL plugin. 3 | 4 | # Usage # 5 | Execute the following: 6 | 1. Update if needed and run *00-installTools.ps1*. It will download and extract to tools directory SqlCodeGuard, SonarScanner and SQLClover. 7 | 2. Update *01-executeDBChanges.ps1* with *server* name where to deploy tSQLt framework and run. 8 | 3. Publish database from src folder. 9 | 4. Update *server* and *sonarHost* parameters in *02-runSonar.ps1* file and run that script. 10 | 11 | TSQL sample project should now be visible in SonarQube server with coverage results depicted in the figure. 12 | 13 | ![TSQLT example project in Sonar](imgs/sonarDashboard.png) 14 | 15 | -------------------------------------------------------------------------------- /examples/example3-full/imgs/sonarDashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gretard/sonar-tsql-plugin/aadb5598bbb183c12df997ee9f3e053f962ce0f7/examples/example3-full/imgs/sonarDashboard.png -------------------------------------------------------------------------------- /examples/example3-full/src/ExampleDatabase/ExampleDatabase.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2026 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "ExampleDatabase", "ExampleDatabase\ExampleDatabase.sqlproj", "{1EE51303-9E3E-49F4-BCAC-92E9F5758931}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {1EE51303-9E3E-49F4-BCAC-92E9F5758931}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {1EE51303-9E3E-49F4-BCAC-92E9F5758931}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {1EE51303-9E3E-49F4-BCAC-92E9F5758931}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 17 | {1EE51303-9E3E-49F4-BCAC-92E9F5758931}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {1EE51303-9E3E-49F4-BCAC-92E9F5758931}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {1EE51303-9E3E-49F4-BCAC-92E9F5758931}.Release|Any CPU.Deploy.0 = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | GlobalSection(ExtensibilityGlobals) = postSolution 25 | SolutionGuid = {5391EDB2-010B-469F-8931-BD24084B38FF} 26 | EndGlobalSection 27 | EndGlobal 28 | -------------------------------------------------------------------------------- /examples/example3-full/src/ExampleDatabase/ExampleDatabase/.gitignore: -------------------------------------------------------------------------------- 1 | /ExampleDatabase.sqlproj.user 2 | **/bin/**/* 3 | **/obj/**/* 4 | -------------------------------------------------------------------------------- /examples/example3-full/src/ExampleDatabase/ExampleDatabase/Billing.sql: -------------------------------------------------------------------------------- 1 | CREATE SCHEMA [Billing] 2 | AUTHORIZATION [dbo]; 3 | 4 | -------------------------------------------------------------------------------- /examples/example3-full/src/ExampleDatabase/ExampleDatabase/Billing/CustomerDiscounts.sql: -------------------------------------------------------------------------------- 1 | CREATE VIEW [Billing].[CustomerDiscounts] 2 | AS 3 | SELECT *, CASE WHEN [Billing].IsCustomerEligibleForDiscount(id) = 1 THEN 'discount available' ELSE 'no discount' END AS 'discount options' 4 | FROM billing.Customers -------------------------------------------------------------------------------- /examples/example3-full/src/ExampleDatabase/ExampleDatabase/Billing/Customers.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Billing].[Customers] ( 2 | [id] INT NULL, 3 | [name] NCHAR (255) NULL 4 | ); 5 | 6 | 7 | GO 8 | EXECUTE sp_addextendedproperty @name = N'tSQLt.FakeTable_OrgTableName', @value = N'tSQLt_tempobject_9ebb1c5d4b6944daace9941ebca2c6bc', @level0type = N'SCHEMA', @level0name = N'Billing', @level1type = N'TABLE', @level1name = N'Customers'; 9 | 10 | -------------------------------------------------------------------------------- /examples/example3-full/src/ExampleDatabase/ExampleDatabase/Billing/IsCustomerEligibleForDiscount.sql: -------------------------------------------------------------------------------- 1 | CREATE FUNCTION Billing.IsCustomerEligibleForDiscount 2 | ( 3 | @customerId int 4 | ) 5 | RETURNS bit 6 | AS 7 | BEGIN 8 | DECLARE @result bit = 0 9 | DECLARE @date DATETIME = GETDATE(); 10 | DECLARE @prevMonth DATETIME = EOMONTH ( @date, -1 ); 11 | 12 | SELECT @result = case when sum([sum]) > 2000 and count(*) > 3 then 1 else 0 end 13 | FROM Billing.Orders WHERE customerId = @customerId and [date] between @prevMonth and @date 14 | 15 | RETURN @result 16 | 17 | END -------------------------------------------------------------------------------- /examples/example3-full/src/ExampleDatabase/ExampleDatabase/Billing/Orders.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [Billing].[Orders] ( 2 | [ordername] NCHAR (255) NULL, 3 | [customerId] INT NULL, 4 | [sum] FLOAT (53) NULL, 5 | [date] DATE NULL 6 | ); 7 | 8 | 9 | GO 10 | EXECUTE sp_addextendedproperty @name = N'tSQLt.FakeTable_OrgTableName', @value = N'tSQLt_tempobject_f0c30fdb1c4a4fa697445d265ee80788', @level0type = N'SCHEMA', @level0name = N'Billing', @level1type = N'TABLE', @level1name = N'Orders'; 11 | 12 | -------------------------------------------------------------------------------- /examples/example3-full/src/ExampleDatabase/ExampleDatabase/BillingTests.sql: -------------------------------------------------------------------------------- 1 | CREATE SCHEMA [BillingTests] 2 | AUTHORIZATION [dbo]; 3 | 4 | 5 | GO 6 | EXECUTE sp_addextendedproperty @name = N'tSQLt.TestClass', @value = 1, @level0type = N'SCHEMA', @level0name = N'BillingTests'; 7 | 8 | -------------------------------------------------------------------------------- /examples/example3-full/src/ExampleDatabase/ExampleDatabase/BillingTests/test that customer with more than 3 orders and total over 2000 can discount.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE [BillingTests].[test that customer with more than 3 orders and total over 2000 can discount] 3 | AS 4 | BEGIN 5 | --Assemble: Fake the Particle table to make sure it is empty and that constraints will not be a problem 6 | EXEC tSQLt.FakeTable 'Billing.Customers'; 7 | EXEC tSQLt.FakeTable 'Billing.Orders'; 8 | -- Populate the Particle table with rows that hug the rectangle boundaries 9 | INSERT INTO Billing.Customers VALUES ( 1, 'test'); 10 | INSERT INTO Billing.Orders VALUES ('order1', 1, 1000, DATEADD(day,-1,GETDATE())); 11 | INSERT INTO Billing.Orders VALUES ('order2', 1, 2000, DATEADD(day,-1,GETDATE())); 12 | INSERT INTO Billing.Orders VALUES ('order3', 1, 3330, DATEADD(day,-1,GETDATE())); 13 | INSERT INTO Billing.Orders VALUES ('order4', 1, 12220, DATEADD(day,-1,GETDATE())); 14 | DECLARE @actualComputedResult BIT; 15 | SET @actualComputedResult = Billing.IsCustomerEligibleForDiscount(1); 16 | EXEC tSQLt.AssertEquals 1, @actualComputedResult; 17 | END; -------------------------------------------------------------------------------- /examples/example3-full/src/ExampleDatabase/ExampleDatabase/BillingTests/test that not existing customer can not get discount.sql: -------------------------------------------------------------------------------- 1 |  2 | CREATE PROCEDURE [BillingTests].[test that not existing customer can not get discount] 3 | AS 4 | BEGIN 5 | EXEC tSQLt.FakeTable 'Billing.Customers'; 6 | EXEC tSQLt.FakeTable 'Billing.Orders'; 7 | DECLARE @actualComputedResult BIT; 8 | SET @actualComputedResult = Billing.IsCustomerEligibleForDiscount(1); 9 | EXEC tSQLt.AssertEquals 0, @actualComputedResult; 10 | END; -------------------------------------------------------------------------------- /examples/example4-adhoc/Example.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "Example", "Example\Example.sqlproj", "{1491DCE3-0018-487C-9B9B-F7EEA6C863F8}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {1491DCE3-0018-487C-9B9B-F7EEA6C863F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {1491DCE3-0018-487C-9B9B-F7EEA6C863F8}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {1491DCE3-0018-487C-9B9B-F7EEA6C863F8}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 17 | {1491DCE3-0018-487C-9B9B-F7EEA6C863F8}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {1491DCE3-0018-487C-9B9B-F7EEA6C863F8}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {1491DCE3-0018-487C-9B9B-F7EEA6C863F8}.Release|Any CPU.Deploy.0 = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | EndGlobal 25 | -------------------------------------------------------------------------------- /examples/example4-adhoc/Example/TestTable.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE [dbo].[TestTable] 2 | ( 3 | [Id] INT NOT NULL PRIMARY KEY, 4 | [Name] NVARCHAR(MAX) NULL 5 | ) 6 | -------------------------------------------------------------------------------- /examples/example4-adhoc/Example/sp_Get.sql: -------------------------------------------------------------------------------- 1 | CREATE PROCEDURE [dbo].[sp_Get] 2 | @param1 int = 0, 3 | @param2 int 4 | AS 5 | BEGIN 6 | SELECT * FROM TestTable; 7 | EXEC ('SELECT 1'); 8 | insert into dbo.test values (1,2); 9 | 10 | EXECUTE sp_executesql N'select 1'; 11 | 12 | RETURN 0 13 | END 14 | -- kasldjaskjd -------------------------------------------------------------------------------- /examples/example4-adhoc/README.md: -------------------------------------------------------------------------------- 1 | # Example T-SQL project 2 | In order to get results to sonar server please: 3 | 4 | - (Optional) Please update file **myExampleRepo.customRules** in *customRules* directory with your custom rules 5 | - (Optional) If needed update path to SQL code guard on sonar server or add **sonar.tsql.cg.path** setting with path in sonar.properties file 6 | - (Optional) Build sample project with setting /p:RunSqlCodeAnalysis=true if not using other means for building: 7 | - msbuild /p:RunSqlCodeAnalysis=true 8 | - (Optional) Update sonar-project.properties file as needed 9 | - Run sonar scanner 10 | -------------------------------------------------------------------------------- /examples/example4-adhoc/sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectKey=example4.tsql.project.adhoc 2 | sonar.projectName=Example4: TSQL project with Adhoc rules 3 | sonar.projectVersion=1.0 4 | sonar.sources=Example 5 | sonar.sourceEncoding=UTF-8 6 | sonar.language=tsql 7 | sonar.tsql.customrules.paths=./customRules 8 | ## not needed to update if matches server settings 9 | #sonar.tsql.customrules.prefix=.customRules 10 | -------------------------------------------------------------------------------- /scripts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scripts", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "cheerio": "^1.0.0-rc.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.scannerwork/ 3 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | sonar-tsql-plugin 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.sonar.ide.eclipse.core.sonarNature 21 | org.eclipse.jdt.core.javanature 22 | org.eclipse.m2e.core.maven2Nature 23 | 24 | 25 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/opencover/Classes.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.08.15 at 09:03:12 PM EEST 6 | // 7 | 8 | 9 | package org.opencover; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import javax.xml.bind.annotation.XmlAccessType; 14 | import javax.xml.bind.annotation.XmlAccessorType; 15 | import javax.xml.bind.annotation.XmlElement; 16 | import javax.xml.bind.annotation.XmlRootElement; 17 | import javax.xml.bind.annotation.XmlType; 18 | 19 | 20 | /** 21 | *

Java class for anonymous complex type. 22 | * 23 | *

The following schema fragment specifies the expected content contained within this class. 24 | * 25 | *

26 |  * <complexType>
27 |  *   <complexContent>
28 |  *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
29 |  *       <sequence>
30 |  *         <element ref="{}Class" maxOccurs="unbounded" minOccurs="0"/>
31 |  *       </sequence>
32 |  *     </restriction>
33 |  *   </complexContent>
34 |  * </complexType>
35 |  * 
36 | * 37 | * 38 | */ 39 | @XmlAccessorType(XmlAccessType.FIELD) 40 | @XmlType(name = "", propOrder = { 41 | "clazz" 42 | }) 43 | @XmlRootElement(name = "Classes") 44 | public class Classes { 45 | 46 | @XmlElement(name = "Class") 47 | protected List clazz; 48 | 49 | /** 50 | * Gets the value of the clazz property. 51 | * 52 | *

53 | * This accessor method returns a reference to the live list, 54 | * not a snapshot. Therefore any modification you make to the 55 | * returned list will be present inside the JAXB object. 56 | * This is why there is not a set method for the clazz property. 57 | * 58 | *

59 | * For example, to add a new item, do as follows: 60 | *

61 |      *    getClazz().add(newItem);
62 |      * 
63 | * 64 | * 65 | *

66 | * Objects of the following type(s) are allowed in the list 67 | * {@link Class } 68 | * 69 | * 70 | */ 71 | public List getClazz() { 72 | if (clazz == null) { 73 | clazz = new ArrayList(); 74 | } 75 | return this.clazz; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/opencover/CoverageSession.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.08.15 at 09:03:12 PM EEST 6 | // 7 | 8 | 9 | package org.opencover; 10 | 11 | import javax.xml.bind.annotation.XmlAccessType; 12 | import javax.xml.bind.annotation.XmlAccessorType; 13 | import javax.xml.bind.annotation.XmlElement; 14 | import javax.xml.bind.annotation.XmlRootElement; 15 | import javax.xml.bind.annotation.XmlType; 16 | 17 | 18 | /** 19 | *

Java class for anonymous complex type. 20 | * 21 | *

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="{}Summary"/>
 29 |  *         <element ref="{}Modules"/>
 30 |  *       </sequence>
 31 |  *     </restriction>
 32 |  *   </complexContent>
 33 |  * </complexType>
 34 |  * 
35 | * 36 | * 37 | */ 38 | @XmlAccessorType(XmlAccessType.FIELD) 39 | @XmlType(name = "", propOrder = { 40 | "summary", 41 | "modules" 42 | }) 43 | @XmlRootElement(name = "CoverageSession") 44 | public class CoverageSession { 45 | 46 | @XmlElement(name = "Summary", required = true) 47 | protected Summary summary; 48 | @XmlElement(name = "Modules", required = true) 49 | protected Modules modules; 50 | 51 | /** 52 | * Gets the value of the summary property. 53 | * 54 | * @return 55 | * possible object is 56 | * {@link Summary } 57 | * 58 | */ 59 | public Summary getSummary() { 60 | return summary; 61 | } 62 | 63 | /** 64 | * Sets the value of the summary property. 65 | * 66 | * @param value 67 | * allowed object is 68 | * {@link Summary } 69 | * 70 | */ 71 | public void setSummary(Summary value) { 72 | this.summary = value; 73 | } 74 | 75 | /** 76 | * Gets the value of the modules property. 77 | * 78 | * @return 79 | * possible object is 80 | * {@link Modules } 81 | * 82 | */ 83 | public Modules getModules() { 84 | return modules; 85 | } 86 | 87 | /** 88 | * Sets the value of the modules property. 89 | * 90 | * @param value 91 | * allowed object is 92 | * {@link Modules } 93 | * 94 | */ 95 | public void setModules(Modules value) { 96 | this.modules = value; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/opencover/FileRef.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.08.15 at 09:03:12 PM EEST 6 | // 7 | 8 | 9 | package org.opencover; 10 | 11 | import javax.xml.bind.annotation.XmlAccessType; 12 | import javax.xml.bind.annotation.XmlAccessorType; 13 | import javax.xml.bind.annotation.XmlAttribute; 14 | import javax.xml.bind.annotation.XmlRootElement; 15 | import javax.xml.bind.annotation.XmlType; 16 | import javax.xml.bind.annotation.XmlValue; 17 | 18 | 19 | /** 20 | *

Java class for anonymous complex type. 21 | * 22 | *

The following schema fragment specifies the expected content contained within this class. 23 | * 24 | *

25 |  * <complexType>
26 |  *   <simpleContent>
27 |  *     <extension base="<http://www.w3.org/2001/XMLSchema>string">
28 |  *       <attribute name="uid" type="{http://www.w3.org/2001/XMLSchema}int" />
29 |  *     </extension>
30 |  *   </simpleContent>
31 |  * </complexType>
32 |  * 
33 | * 34 | * 35 | */ 36 | @XmlAccessorType(XmlAccessType.FIELD) 37 | @XmlType(name = "", propOrder = { 38 | "value" 39 | }) 40 | @XmlRootElement(name = "FileRef") 41 | public class FileRef { 42 | 43 | @XmlValue 44 | protected String value; 45 | @XmlAttribute(name = "uid") 46 | protected Integer uid; 47 | 48 | /** 49 | * Gets the value of the value property. 50 | * 51 | * @return 52 | * possible object is 53 | * {@link String } 54 | * 55 | */ 56 | public String getValue() { 57 | return value; 58 | } 59 | 60 | /** 61 | * Sets the value of the value property. 62 | * 63 | * @param value 64 | * allowed object is 65 | * {@link String } 66 | * 67 | */ 68 | public void setValue(String value) { 69 | this.value = value; 70 | } 71 | 72 | /** 73 | * Gets the value of the uid property. 74 | * 75 | * @return 76 | * possible object is 77 | * {@link Integer } 78 | * 79 | */ 80 | public Integer getUid() { 81 | return uid; 82 | } 83 | 84 | /** 85 | * Sets the value of the uid property. 86 | * 87 | * @param value 88 | * allowed object is 89 | * {@link Integer } 90 | * 91 | */ 92 | public void setUid(Integer value) { 93 | this.uid = value; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/opencover/Files.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.08.15 at 09:03:12 PM EEST 6 | // 7 | 8 | 9 | package org.opencover; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import javax.xml.bind.annotation.XmlAccessType; 14 | import javax.xml.bind.annotation.XmlAccessorType; 15 | import javax.xml.bind.annotation.XmlElement; 16 | import javax.xml.bind.annotation.XmlRootElement; 17 | import javax.xml.bind.annotation.XmlType; 18 | 19 | 20 | /** 21 | *

Java class for anonymous complex type. 22 | * 23 | *

The following schema fragment specifies the expected content contained within this class. 24 | * 25 | *

26 |  * <complexType>
27 |  *   <complexContent>
28 |  *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
29 |  *       <sequence>
30 |  *         <element ref="{}File" maxOccurs="unbounded" minOccurs="0"/>
31 |  *       </sequence>
32 |  *     </restriction>
33 |  *   </complexContent>
34 |  * </complexType>
35 |  * 
36 | * 37 | * 38 | */ 39 | @XmlAccessorType(XmlAccessType.FIELD) 40 | @XmlType(name = "", propOrder = { 41 | "file" 42 | }) 43 | @XmlRootElement(name = "Files") 44 | public class Files { 45 | 46 | @XmlElement(name = "File") 47 | protected List file; 48 | 49 | /** 50 | * Gets the value of the file property. 51 | * 52 | *

53 | * This accessor method returns a reference to the live list, 54 | * not a snapshot. Therefore any modification you make to the 55 | * returned list will be present inside the JAXB object. 56 | * This is why there is not a set method for the file property. 57 | * 58 | *

59 | * For example, to add a new item, do as follows: 60 | *

61 |      *    getFile().add(newItem);
62 |      * 
63 | * 64 | * 65 | *

66 | * Objects of the following type(s) are allowed in the list 67 | * {@link File } 68 | * 69 | * 70 | */ 71 | public List getFile() { 72 | if (file == null) { 73 | file = new ArrayList(); 74 | } 75 | return this.file; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/opencover/Methods.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.08.15 at 09:03:12 PM EEST 6 | // 7 | 8 | 9 | package org.opencover; 10 | 11 | import javax.xml.bind.annotation.XmlAccessType; 12 | import javax.xml.bind.annotation.XmlAccessorType; 13 | import javax.xml.bind.annotation.XmlElement; 14 | import javax.xml.bind.annotation.XmlRootElement; 15 | import javax.xml.bind.annotation.XmlType; 16 | 17 | 18 | /** 19 | *

Java class for anonymous complex type. 20 | * 21 | *

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="{}Method"/>
29 |  *       </sequence>
30 |  *     </restriction>
31 |  *   </complexContent>
32 |  * </complexType>
33 |  * 
34 | * 35 | * 36 | */ 37 | @XmlAccessorType(XmlAccessType.FIELD) 38 | @XmlType(name = "", propOrder = { 39 | "method" 40 | }) 41 | @XmlRootElement(name = "Methods") 42 | public class Methods { 43 | 44 | @XmlElement(name = "Method", required = true) 45 | protected Method method; 46 | 47 | /** 48 | * Gets the value of the method property. 49 | * 50 | * @return 51 | * possible object is 52 | * {@link Method } 53 | * 54 | */ 55 | public Method getMethod() { 56 | return method; 57 | } 58 | 59 | /** 60 | * Sets the value of the method property. 61 | * 62 | * @param value 63 | * allowed object is 64 | * {@link Method } 65 | * 66 | */ 67 | public void setMethod(Method value) { 68 | this.method = value; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/opencover/Modules.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.08.15 at 09:03:12 PM EEST 6 | // 7 | 8 | 9 | package org.opencover; 10 | 11 | import javax.xml.bind.annotation.XmlAccessType; 12 | import javax.xml.bind.annotation.XmlAccessorType; 13 | import javax.xml.bind.annotation.XmlElement; 14 | import javax.xml.bind.annotation.XmlRootElement; 15 | import javax.xml.bind.annotation.XmlType; 16 | 17 | 18 | /** 19 | *

Java class for anonymous complex type. 20 | * 21 | *

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="{}Module"/>
29 |  *       </sequence>
30 |  *     </restriction>
31 |  *   </complexContent>
32 |  * </complexType>
33 |  * 
34 | * 35 | * 36 | */ 37 | @XmlAccessorType(XmlAccessType.FIELD) 38 | @XmlType(name = "", propOrder = { 39 | "module" 40 | }) 41 | @XmlRootElement(name = "Modules") 42 | public class Modules { 43 | 44 | @XmlElement(name = "Module", required = true) 45 | protected Module module; 46 | 47 | /** 48 | * Gets the value of the module property. 49 | * 50 | * @return 51 | * possible object is 52 | * {@link Module } 53 | * 54 | */ 55 | public Module getModule() { 56 | return module; 57 | } 58 | 59 | /** 60 | * Sets the value of the module property. 61 | * 62 | * @param value 63 | * allowed object is 64 | * {@link Module } 65 | * 66 | */ 67 | public void setModule(Module value) { 68 | this.module = value; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/opencover/SequencePoints.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.08.15 at 09:03:12 PM EEST 6 | // 7 | 8 | 9 | package org.opencover; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import javax.xml.bind.annotation.XmlAccessType; 14 | import javax.xml.bind.annotation.XmlAccessorType; 15 | import javax.xml.bind.annotation.XmlElement; 16 | import javax.xml.bind.annotation.XmlRootElement; 17 | import javax.xml.bind.annotation.XmlType; 18 | 19 | 20 | /** 21 | *

Java class for anonymous complex type. 22 | * 23 | *

The following schema fragment specifies the expected content contained within this class. 24 | * 25 | *

26 |  * <complexType>
27 |  *   <complexContent>
28 |  *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
29 |  *       <sequence>
30 |  *         <element ref="{}SequencePoint" maxOccurs="unbounded" minOccurs="0"/>
31 |  *       </sequence>
32 |  *     </restriction>
33 |  *   </complexContent>
34 |  * </complexType>
35 |  * 
36 | * 37 | * 38 | */ 39 | @XmlAccessorType(XmlAccessType.FIELD) 40 | @XmlType(name = "", propOrder = { 41 | "sequencePoint" 42 | }) 43 | @XmlRootElement(name = "SequencePoints") 44 | public class SequencePoints { 45 | 46 | @XmlElement(name = "SequencePoint") 47 | protected List sequencePoint; 48 | 49 | /** 50 | * Gets the value of the sequencePoint property. 51 | * 52 | *

53 | * This accessor method returns a reference to the live list, 54 | * not a snapshot. Therefore any modification you make to the 55 | * returned list will be present inside the JAXB object. 56 | * This is why there is not a set method for the sequencePoint property. 57 | * 58 | *

59 | * For example, to add a new item, do as follows: 60 | *

61 |      *    getSequencePoint().add(newItem);
62 |      * 
63 | * 64 | * 65 | *

66 | * Objects of the following type(s) are allowed in the list 67 | * {@link SequencePoint } 68 | * 69 | * 70 | */ 71 | public List getSequencePoint() { 72 | if (sequencePoint == null) { 73 | sequencePoint = new ArrayList(); 74 | } 75 | return this.sequencePoint; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/Constants.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql; 2 | 3 | import org.sonar.plugins.tsql.languages.TSQLLanguage; 4 | 5 | public final class Constants { 6 | public static final String PROFILE_NAME = "Sonar Way"; 7 | 8 | public static final String CG_REPORT_FILE = "sonar.tsql.cg.report"; 9 | 10 | public static final String CG_REPORT_FILE_DEFAULT_VALUE = "cgresults.xml"; 11 | 12 | public static final String PLUGIN_SKIP = "sonar.tsql.skip"; 13 | 14 | public static final String PLUGIN_SKIP_COVERAGE = "sonar.tsql.sqlcover.skip"; 15 | 16 | public static final String PLUGIN_SKIP_CUSTOM = "sonar.tsql.custom.skip"; 17 | 18 | public static final String PLUGIN_SKIP_MS = "sonar.tsql.ms.skip"; 19 | 20 | public static final String PLUGIN_SKIP_CG = "sonar.tsql.cg.skip"; 21 | 22 | public static final String PLUGIN_MAX_FILE_SIZE = "sonar.tsql.custom.max.file.size"; 23 | 24 | public static final String CG_APP_PATH = "sonar.tsql.cg.path"; 25 | 26 | public static final String COVERAGE_FILE = "sonar.tsql.sqlcover.report"; 27 | 28 | public static final String COVERAGE_FILE_DEFAULT_VALUE = "Coverage.opencoverxml"; 29 | 30 | public static final String MS_REPORT_FILE = "sonar.tsql.ms.report"; 31 | 32 | public static final String MS_REPORT_FILE_DEFAULT_VALUE = "staticcodeanalysis.results.xml"; 33 | 34 | public static final String PLUGIN_ANALYSIS_TIMEOUT = "sonar.tsql.timeout.analysis"; 35 | 36 | public static final String PLUGIN_SUFFIXES = "sonar.tsql.file.suffixes"; 37 | 38 | public static final String PLUGIN_SKIP_CUSTOM_RULES = "sonar.tsql.skip.custom.rules"; 39 | 40 | public static final String CG_REPO_KEY = TSQLLanguage.KEY.toLowerCase() + "-sqlcodeguard"; 41 | 42 | public static final String CG_REPO_NAME = TSQLLanguage.KEY.toLowerCase() + " SQL Code Guard"; 43 | 44 | public static final String CG_RULES_FILE = "/rules/cgsql-rules.xml"; 45 | 46 | public static final String MS_REPO_KEY = TSQLLanguage.KEY.toLowerCase() + "-mssql"; 47 | 48 | public static final String MS_REPO_NAME = TSQLLanguage.KEY.toLowerCase() + " Microsoft T-SQL"; 49 | 50 | public static final String MS_RULES_FILE = "/rules/vssql-rules.xml"; 51 | 52 | public static final String PLUGIN_CUSTOM_RULES_PATH = "sonar.tsql.customrules.paths"; 53 | 54 | public static final String PLUGIN_CUSTOM_RULES_PREFIX = "sonar.tsql.customrules.prefix"; 55 | 56 | public static final String PLUGIN_RULES_FILE = "/rules/plugin-rules.xml"; 57 | 58 | public static final String PLUGIN_REPO_NAME = TSQLLanguage.KEY.toLowerCase() + " plugin custom rules"; 59 | 60 | public static final String PLUGIN_REPO_KEY = "tsqlPluginRepo"; 61 | } 62 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/AntlrContext.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.nio.charset.Charset; 6 | 7 | import org.antlr.tsql.TSqlLexer; 8 | import org.antlr.tsql.TSqlParser; 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.Token; 13 | import org.antlr.v4.runtime.tree.ParseTree; 14 | import org.sonar.api.batch.fs.InputFile; 15 | import org.sonar.plugins.tsql.lines.SourceLine; 16 | import org.sonar.plugins.tsql.lines.SourceLinesProvider; 17 | 18 | public class AntlrContext { 19 | 20 | public InputFile getFile() { 21 | return file; 22 | } 23 | 24 | public CommonTokenStream getStream() { 25 | return stream; 26 | } 27 | 28 | public SourceLine[] getLines() { 29 | return lines; 30 | } 31 | 32 | public Token[] getTokens() { 33 | return this.stream.getTokens().toArray(new Token[0]); 34 | } 35 | 36 | public ParseTree getRoot() { 37 | return root; 38 | } 39 | 40 | public int[] getLineAndColumn(final int global) { 41 | 42 | for (final SourceLine line : this.lines) { 43 | if (line.getEnd() > global) { 44 | return new int[] { line.getLine(), global - line.getStart() }; 45 | } 46 | } 47 | return null; 48 | } 49 | 50 | private final InputFile file; 51 | private final CommonTokenStream stream; 52 | private final SourceLine[] lines; 53 | private final ParseTree root; 54 | 55 | public AntlrContext(InputFile file, CommonTokenStream stream, ParseTree root, SourceLine[] lines) { 56 | this.file = file; 57 | this.stream = stream; 58 | this.root = root; 59 | this.lines = lines; 60 | } 61 | 62 | public static AntlrContext fromInputFile(InputFile file, Charset charset) throws IOException { 63 | return fromStreams(file, file.inputStream(), file.inputStream(), charset); 64 | } 65 | 66 | public static AntlrContext fromStreams(InputFile inputFile, InputStream file, InputStream linesStream, 67 | Charset charset) throws IOException { 68 | final SourceLinesProvider linesProvider = new SourceLinesProvider(); 69 | final CharStream charStream = new CaseChangingCharStream(CharStreams.fromStream(file, charset), true); 70 | final TSqlLexer lexer = new TSqlLexer(charStream); 71 | lexer.removeErrorListeners(); 72 | final CommonTokenStream stream = new CommonTokenStream(lexer); 73 | stream.fill(); 74 | final TSqlParser parser = new TSqlParser(stream); 75 | parser.removeErrorListeners(); 76 | final ParseTree root = parser.tsql_file(); 77 | final SourceLine[] lines = linesProvider.getLines(linesStream, charset); 78 | return new AntlrContext(inputFile, stream, root, lines); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/CandidateNode.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr; 2 | 3 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 4 | 5 | public class CandidateNode { 6 | private final CandidateRule rule; 7 | private final IParsedNode nnode; 8 | 9 | public CandidateNode(final CandidateRule rule, final IParsedNode nnode) { 10 | this.rule = rule; 11 | this.nnode = nnode; 12 | } 13 | 14 | public String getRepoKey() { 15 | return this.rule.getKey(); 16 | } 17 | public String getKey() { 18 | return this.rule.getRule().getKey(); 19 | } 20 | public boolean isAdhoc() { 21 | return this.rule.isAdHoc(); 22 | } 23 | 24 | public RuleImplementation getRuleImplementation() { 25 | return this.rule.getRuleImplementation(); 26 | } 27 | 28 | public IParsedNode getNode() { 29 | return nnode; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/CandidateRule.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr; 2 | 3 | import org.sonar.plugins.tsql.checks.custom.Rule; 4 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 5 | 6 | public class CandidateRule { 7 | private final String key; 8 | private final Rule rule; 9 | private final boolean isAdHoc; 10 | 11 | public boolean isAdHoc() { 12 | return isAdHoc; 13 | } 14 | 15 | public String getKey() { 16 | return key; 17 | } 18 | 19 | public Rule getRule() { 20 | return rule; 21 | } 22 | 23 | public CandidateRule(final String key, final Rule rule) { 24 | this(key, rule, false); 25 | } 26 | 27 | public CandidateRule(final String key, final Rule rule, boolean isAdhoc) { 28 | this.key = key; 29 | this.rule = rule; 30 | this.isAdHoc = isAdhoc; 31 | } 32 | 33 | public RuleImplementation getRuleImplementation() { 34 | return this.rule.getRuleImplementation(); 35 | } 36 | 37 | @Override 38 | public int hashCode() { 39 | final int prime = 31; 40 | int result = 1; 41 | result = prime * result + ((key == null) ? 0 : key.hashCode()); 42 | result = prime * result + ((rule == null) ? 0 : rule.hashCode()); 43 | return result; 44 | } 45 | 46 | @Override 47 | public boolean equals(Object obj) { 48 | if (this == obj) 49 | return true; 50 | if (obj == null) 51 | return false; 52 | if (getClass() != obj.getClass()) 53 | return false; 54 | CandidateRule other = (CandidateRule) obj; 55 | if (key == null) { 56 | if (other.key != null) 57 | return false; 58 | } else if (!key.equals(other.key)) 59 | return false; 60 | if (rule == null) { 61 | if (other.rule != null) 62 | return false; 63 | } else if (!rule.equals(other.rule)) 64 | return false; 65 | return true; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/CaseChangingCharStream.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr; 2 | 3 | import org.antlr.v4.runtime.CharStream; 4 | import org.antlr.v4.runtime.misc.Interval; 5 | 6 | public class CaseChangingCharStream implements CharStream { 7 | 8 | private final CharStream stream; 9 | private final boolean upper; 10 | 11 | public CaseChangingCharStream(final CharStream stream, final boolean upper) { 12 | this.stream = stream; 13 | this.upper = upper; 14 | } 15 | 16 | @Override 17 | public String getText(Interval interval) { 18 | return stream.getText(interval); 19 | } 20 | 21 | @Override 22 | public void consume() { 23 | stream.consume(); 24 | } 25 | 26 | @Override 27 | public int LA(int i) { 28 | int c = stream.LA(i); 29 | if (c <= 0) { 30 | return c; 31 | } 32 | if (upper) { 33 | return Character.toUpperCase(c); 34 | } 35 | return Character.toLowerCase(c); 36 | } 37 | 38 | @Override 39 | public int mark() { 40 | return stream.mark(); 41 | } 42 | 43 | @Override 44 | public void release(int marker) { 45 | stream.release(marker); 46 | } 47 | 48 | @Override 49 | public int index() { 50 | return stream.index(); 51 | } 52 | 53 | @Override 54 | public void seek(int index) { 55 | stream.seek(index); 56 | } 57 | 58 | @Override 59 | public int size() { 60 | return stream.size(); 61 | } 62 | 63 | @Override 64 | public String getSourceName() { 65 | return stream.getSourceName(); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/IParsedNode.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr; 2 | 3 | import org.antlr.v4.runtime.tree.ParseTree; 4 | 5 | public interface IParsedNode { 6 | 7 | public String getText(); 8 | 9 | public String getClassName(); 10 | 11 | public int getDistance(); 12 | 13 | public int getIndex(); 14 | 15 | public int getIndex2(); 16 | 17 | public ParseTree getItem(); 18 | 19 | public IParsedNode[] getParents(); 20 | 21 | public IParsedNode[] getChildren(); 22 | 23 | public IParsedNode[] getSiblings(); 24 | 25 | public IParsedNode getControlFlowParent(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/PluginHelper.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.StringWriter; 8 | import java.nio.charset.Charset; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import javax.xml.bind.JAXBContext; 13 | import javax.xml.bind.JAXBException; 14 | import javax.xml.bind.Marshaller; 15 | 16 | import org.antlr.tsql.TSqlLexer; 17 | import org.antlr.tsql.TSqlParser; 18 | import org.antlr.v4.runtime.CharStream; 19 | import org.antlr.v4.runtime.CharStreams; 20 | import org.antlr.v4.runtime.CommonTokenStream; 21 | import org.antlr.v4.runtime.tree.ParseTree; 22 | import org.apache.commons.io.input.BOMInputStream; 23 | import org.sonar.api.batch.fs.InputFile; 24 | import org.sonar.plugins.tsql.checks.custom.Rule; 25 | import org.sonar.plugins.tsql.checks.custom.SqlRules; 26 | import org.sonar.plugins.tsql.lines.SourceLinesProvider; 27 | 28 | public final class PluginHelper { 29 | 30 | 31 | 32 | 33 | 34 | 35 | public static AntlrContext createRequestFromStream(final InputFile file, final Charset encoding, 36 | final CharStream mainStream, InputStream fileInputStream) { 37 | final SourceLinesProvider linesProvider = new SourceLinesProvider(); 38 | final CharStream charStream = new CaseChangingCharStream(mainStream, true); 39 | final TSqlLexer lexer = new TSqlLexer(charStream); 40 | 41 | lexer.removeErrorListeners(); 42 | 43 | final CommonTokenStream stream = new CommonTokenStream(lexer); 44 | 45 | stream.fill(); 46 | final TSqlParser parser = new TSqlParser(stream); 47 | parser.removeErrorListeners(); 48 | final ParseTree root = parser.tsql_file(); 49 | final AntlrContext antrlFile = new AntlrContext(file, stream, root, 50 | linesProvider.getLines(fileInputStream, encoding)); 51 | return antrlFile; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/issues/CustomIssuesProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.issues; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import org.sonar.plugins.tsql.antlr.AntlrContext; 8 | import org.sonar.plugins.tsql.antlr.CandidateNode; 9 | import org.sonar.plugins.tsql.antlr.IParsedNode; 10 | import org.sonar.plugins.tsql.antlr.lines.DefaultLinesProvider; 11 | import org.sonar.plugins.tsql.antlr.nodes.NodeUsesProvider; 12 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 13 | import org.sonar.plugins.tsql.rules.issues.TsqlIssue; 14 | 15 | public class CustomIssuesProvider { 16 | 17 | public TsqlIssue[] getIssues(AntlrContext antlrContext, CandidateNode[] candidates) { 18 | final org.sonar.plugins.tsql.antlr.issues.FoundViolationsAnalyzer foundViolationsAnalyzer = new FoundViolationsAnalyzer( 19 | new DefaultLinesProvider(antlrContext.getStream())); 20 | 21 | final NodesMatchingRulesProvider nodesMatchingRulesProvider = new NodesMatchingRulesProvider( 22 | new NodeUsesProvider(antlrContext.getRoot())); 23 | 24 | final List issues = new ArrayList<>(); 25 | 26 | for (final CandidateNode candidate : candidates) { 27 | final Map> results = nodesMatchingRulesProvider.check(candidate); 28 | final List foundIssues = foundViolationsAnalyzer.analyze(candidate, results); 29 | issues.addAll(foundIssues); 30 | } 31 | return issues.toArray(new TsqlIssue[0]); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/lines/DefaultLinesProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.lines; 2 | 3 | import org.antlr.v4.runtime.CommonTokenStream; 4 | import org.antlr.v4.runtime.Token; 5 | import org.antlr.v4.runtime.misc.Interval; 6 | import org.sonar.plugins.tsql.antlr.IParsedNode; 7 | 8 | public class DefaultLinesProvider implements ILinesProvider { 9 | 10 | private final CommonTokenStream stream; 11 | 12 | public DefaultLinesProvider(final CommonTokenStream stream) { 13 | this.stream = stream; 14 | } 15 | 16 | @Override 17 | public int getLine(final IParsedNode node) { 18 | if (node == null || node.getItem() == null) { 19 | return 0; 20 | } 21 | final Interval sourceInterval = node.getItem().getSourceInterval(); 22 | final Token firstToken = stream.get(sourceInterval.a); 23 | final int line = firstToken.getLine(); 24 | return line; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/lines/ILinesProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.lines; 2 | 3 | import org.sonar.plugins.tsql.antlr.IParsedNode; 4 | import org.sonar.plugins.tsql.antlr.nodes.ParsedNode; 5 | 6 | public interface ILinesProvider { 7 | int getLine(IParsedNode node); 8 | } 9 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/nodes/INodesProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes; 2 | 3 | import org.sonar.plugins.tsql.antlr.IParsedNode; 4 | 5 | public interface INodesProvider { 6 | IParsedNode[] getNodes(final T node); 7 | } 8 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/nodes/NodeUsesProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; 7 | import org.antlr.v4.runtime.tree.ParseTree; 8 | import org.antlr.v4.runtime.tree.RuleNode; 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.sonar.plugins.tsql.antlr.IParsedNode; 11 | 12 | @SuppressWarnings("rawtypes") 13 | public class NodeUsesProvider extends AbstractParseTreeVisitor implements INodesProvider { 14 | 15 | private final ParseTree root; 16 | private final List nodes = new ArrayList<>(); 17 | 18 | private String tempText; 19 | 20 | public NodeUsesProvider(final ParseTree root) { 21 | this.root = root; 22 | } 23 | 24 | @Override 25 | public IParsedNode[] getNodes(final IParsedNode node) { 26 | this.nodes.clear(); 27 | this.tempText = null; 28 | if (node == null) { 29 | return new IParsedNode[0]; 30 | } 31 | this.tempText = node.getText(); 32 | visit(root); 33 | IParsedNode[] results = this.nodes.toArray(new IParsedNode[0]); 34 | this.nodes.clear(); 35 | this.tempText = null; 36 | return results; 37 | 38 | } 39 | 40 | @SuppressWarnings("unchecked") 41 | @Override 42 | public Object visitChildren(final RuleNode node) { 43 | 44 | final int n = node.getChildCount(); 45 | 46 | for (int i = 0; i < n; i++) { 47 | final ParseTree c = node.getChild(i); 48 | c.accept(this); 49 | 50 | } 51 | final String textToFind = node.getText(); 52 | if (StringUtils.containsIgnoreCase(textToFind, tempText) 53 | || StringUtils.containsIgnoreCase(tempText, textToFind)) { 54 | nodes.add(new ParsedNode(node)); 55 | } 56 | return null; 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/nodes/matchers/ABaseMatcher.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes.matchers; 2 | 3 | import org.sonar.plugins.tsql.antlr.IParsedNode; 4 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 5 | 6 | public abstract class ABaseMatcher implements IMatcher { 7 | 8 | protected abstract boolean innerMatch(RuleImplementation rule, IParsedNode item); 9 | 10 | protected abstract boolean shouldApply(RuleImplementation rule, IParsedNode item); 11 | 12 | @Override 13 | public boolean match(RuleImplementation rule, IParsedNode item) { 14 | if (rule == null || item == null) { 15 | return false; 16 | } 17 | if (shouldApply(rule, item)) { 18 | return innerMatch(rule, item); 19 | } 20 | 21 | return true; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/nodes/matchers/ClassNameMatcher.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes.matchers; 2 | 3 | import org.sonar.plugins.tsql.antlr.IParsedNode; 4 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 5 | 6 | public class ClassNameMatcher extends ABaseMatcher { 7 | 8 | private final boolean isStrict; 9 | 10 | public ClassNameMatcher(boolean isStrict) { 11 | this.isStrict = isStrict; 12 | 13 | } 14 | 15 | public ClassNameMatcher() { 16 | this(false); 17 | } 18 | 19 | @Override 20 | protected boolean innerMatch(RuleImplementation rule, IParsedNode item) { 21 | final String name = item.getClassName(); 22 | for (final String classNameToCheck : rule.getNames().getTextItem()) { 23 | if (name.equalsIgnoreCase(classNameToCheck)) { 24 | return true; 25 | } 26 | } 27 | return false; 28 | } 29 | 30 | @Override 31 | protected boolean shouldApply(RuleImplementation rule, IParsedNode item) { 32 | return !rule.getNames().getTextItem().isEmpty() || isStrict; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/nodes/matchers/DistanceMatcher.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes.matchers; 2 | 3 | import org.sonar.plugins.tsql.antlr.IParsedNode; 4 | import org.sonar.plugins.tsql.checks.custom.RuleDistanceIndexMatchType; 5 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 6 | 7 | public class DistanceMatcher extends ABaseMatcher { 8 | 9 | @Override 10 | protected boolean innerMatch(RuleImplementation rule, IParsedNode node) { 11 | 12 | int val = node.getDistance(); 13 | if (rule.getDistanceCheckType() == RuleDistanceIndexMatchType.LESS) { 14 | if (val > rule.getDistance()) { 15 | return false; 16 | } 17 | } 18 | if (rule.getDistanceCheckType() == RuleDistanceIndexMatchType.MORE) { 19 | if (val < rule.getDistance()) { 20 | return false; 21 | } 22 | } 23 | if (rule.getDistanceCheckType() == RuleDistanceIndexMatchType.EQUALS) { 24 | if (rule.getDistance() != val) { 25 | return false; 26 | } 27 | } 28 | return true; 29 | 30 | } 31 | 32 | @Override 33 | protected boolean shouldApply(RuleImplementation rule, IParsedNode item) { 34 | return rule.getDistance() != 0; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/nodes/matchers/IMatcher.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes.matchers; 2 | 3 | import org.sonar.plugins.tsql.antlr.IParsedNode; 4 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 5 | 6 | public interface IMatcher { 7 | boolean match(final RuleImplementation rule, final IParsedNode item); 8 | } 9 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/nodes/matchers/IParentMatcher.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes.matchers; 2 | 3 | import org.sonar.plugins.tsql.antlr.IParsedNode; 4 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 5 | 6 | public interface IParentMatcher { 7 | boolean isMatch(RuleImplementation rule, IParsedNode parent, IParsedNode child); 8 | } 9 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/nodes/matchers/IndexMatcher.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes.matchers; 2 | 3 | import org.sonar.plugins.tsql.antlr.IParsedNode; 4 | import org.sonar.plugins.tsql.checks.custom.RuleDistanceIndexMatchType; 5 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 6 | 7 | public class IndexMatcher extends ABaseMatcher { 8 | 9 | @Override 10 | protected boolean innerMatch(RuleImplementation rule, IParsedNode node) { 11 | if (rule.getIndex() > 0) { 12 | int val = node.getIndex(); 13 | if (rule.getIndexCheckType() == RuleDistanceIndexMatchType.LESS) { 14 | if (val > rule.getIndex()) { 15 | return false; 16 | } 17 | } 18 | if (rule.getIndexCheckType() == RuleDistanceIndexMatchType.EQUALS) { 19 | if (val != rule.getIndex()) { 20 | return false; 21 | } 22 | } 23 | if (rule.getIndexCheckType() == RuleDistanceIndexMatchType.MORE) { 24 | if (rule.getIndex() < val) { 25 | return false; 26 | } 27 | } 28 | 29 | } 30 | if (rule.getIndex() < 0) { 31 | int val = node.getIndex2(); 32 | if (rule.getIndexCheckType() == RuleDistanceIndexMatchType.LESS) { 33 | if (val > rule.getIndex()) { 34 | return false; 35 | } 36 | } 37 | if (rule.getIndexCheckType() == RuleDistanceIndexMatchType.EQUALS) { 38 | if (val != rule.getIndex()) { 39 | return false; 40 | } 41 | } 42 | if (rule.getIndexCheckType() == RuleDistanceIndexMatchType.MORE) { 43 | if (rule.getIndex() < val) { 44 | return false; 45 | } 46 | } 47 | 48 | } 49 | return true; 50 | 51 | } 52 | 53 | @Override 54 | protected boolean shouldApply(RuleImplementation rule, IParsedNode item) { 55 | return rule.getIndex() != 0; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/nodes/matchers/NodeNameAndOrClassMatcher.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes.matchers; 2 | 3 | import org.sonar.plugins.tsql.antlr.IParsedNode; 4 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 5 | 6 | public class NodeNameAndOrClassMatcher implements IMatcher { 7 | 8 | private final IMatcher classMatcher = new ClassNameMatcher(); 9 | private final IMatcher textMatcher = new TextNameMatcher(); 10 | 11 | @Override 12 | public boolean match(RuleImplementation rule, IParsedNode item) { 13 | return this.classMatcher.match(rule, item) && this.textMatcher.match(rule, item); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/nodes/matchers/ParentsMatcher.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes.matchers; 2 | 3 | import org.sonar.plugins.tsql.antlr.IParsedNode; 4 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 5 | 6 | public class ParentsMatcher implements IParentMatcher { 7 | 8 | @Override 9 | public boolean isMatch(RuleImplementation rule, IParsedNode parent, IParsedNode child) { 10 | IParsedNode parent1 = parent.getControlFlowParent(); 11 | IParsedNode parent2 = child.getControlFlowParent(); 12 | 13 | if (parent1 == null || parent2 == null) { 14 | return false; 15 | } 16 | return parent.getControlFlowParent().getItem() == child.getControlFlowParent().getItem(); 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/nodes/matchers/RulesMatcher.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes.matchers; 2 | 3 | import org.sonar.plugins.tsql.antlr.IParsedNode; 4 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 5 | import org.sonar.plugins.tsql.checks.custom.RuleMatchType; 6 | 7 | public class RulesMatcher { 8 | 9 | private final IMatcher[] matchers = new IMatcher[] { new DistanceMatcher(), new IndexMatcher() }; 10 | private final IMatcher classNamesMatcher = new ClassNameMatcher(); 11 | private final IMatcher textMatcher = new TextNameMatcher(); 12 | 13 | private final IParentMatcher sameParentsMatcher = new ParentsMatcher(); 14 | private final IParentMatcher sameTextMatcher = new SameTextMatcher(); 15 | 16 | public boolean match(RuleImplementation rule, IParsedNode parent, IParsedNode node) { 17 | 18 | for (final IMatcher matcher : this.matchers) { 19 | if (!matcher.match(rule, node)) { 20 | return false; 21 | } 22 | } 23 | 24 | final RuleMatchType type = rule.getRuleMatchType(); 25 | 26 | boolean classMatch = classNamesMatcher.match(rule, node); 27 | boolean textMatch = textMatcher.match(rule, node); 28 | switch (type) { 29 | case DEFAULT: 30 | case CLASS_ONLY: 31 | return classMatch; 32 | case TEXT_AND_CLASS: 33 | return classMatch && textMatch; 34 | case TEXT_ONLY: 35 | return textMatch; 36 | case FULL: 37 | if (parent == null) { 38 | throw new IllegalArgumentException("Can't do full check as parent is null"); 39 | } 40 | boolean sameText = sameTextMatcher.isMatch(rule, parent, node); 41 | return textMatch && classMatch && sameText; 42 | case STRICT: 43 | if (parent == null) { 44 | throw new IllegalArgumentException("Can't do strict check as parent is null"); 45 | } 46 | return textMatch && classMatch && sameTextMatcher.isMatch(rule, parent, node) 47 | && sameParentsMatcher.isMatch(rule, node, parent); 48 | default: 49 | break; 50 | } 51 | return false; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/nodes/matchers/SameTextMatcher.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes.matchers; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.sonar.plugins.tsql.antlr.IParsedNode; 5 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 6 | 7 | public class SameTextMatcher implements IParentMatcher { 8 | 9 | @Override 10 | public boolean isMatch(RuleImplementation rule, IParsedNode parent, IParsedNode child) { 11 | String text1 = child.getText(); 12 | String text2 = parent.getText(); 13 | 14 | return StringUtils.contains(text1, text2) || StringUtils.contains(text2, text1); 15 | 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/nodes/matchers/TextNameMatcher.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes.matchers; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.sonar.plugins.tsql.antlr.IParsedNode; 5 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 6 | import org.sonar.plugins.tsql.checks.custom.TextCheckType; 7 | 8 | public class TextNameMatcher extends ABaseMatcher { 9 | private final boolean isStrict; 10 | 11 | public TextNameMatcher(boolean isStrict) { 12 | this.isStrict = isStrict; 13 | } 14 | 15 | public TextNameMatcher() { 16 | this(false); 17 | } 18 | 19 | @Override 20 | protected boolean innerMatch(RuleImplementation rule, IParsedNode item) { 21 | final TextCheckType type = rule.getTextCheckType(); 22 | 23 | final String text = item.getText(); 24 | 25 | for (final String searchItem : rule.getTextToFind().getTextItem()) { 26 | switch (type) { 27 | case DEFAULT: 28 | case CONTAINS: 29 | if (StringUtils.containsIgnoreCase(text, searchItem)) { 30 | return true; 31 | } 32 | break; 33 | 34 | case REGEXP: 35 | if (text.matches(searchItem)) { 36 | return true; 37 | } 38 | break; 39 | case STRICT: 40 | if (text.equalsIgnoreCase(searchItem)) { 41 | return true; 42 | } 43 | break; 44 | default: 45 | break; 46 | } 47 | } 48 | return false; 49 | } 50 | 51 | @Override 52 | protected boolean shouldApply(RuleImplementation rule, IParsedNode item) { 53 | return !rule.getTextToFind().getTextItem().isEmpty() || isStrict; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/visitors/CComplexityVisitor.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.visitors; 2 | 3 | import static java.lang.String.format; 4 | 5 | import org.antlr.tsql.TSqlParser.Search_condition_notContext; 6 | import org.antlr.tsql.TSqlParser.Try_catch_statementContext; 7 | import org.antlr.v4.runtime.tree.ParseTree; 8 | import org.sonar.api.batch.fs.InputFile; 9 | import org.sonar.api.batch.sensor.SensorContext; 10 | import org.sonar.api.measures.CoreMetrics; 11 | import org.sonar.api.utils.log.Logger; 12 | import org.sonar.api.utils.log.Loggers; 13 | import org.sonar.plugins.tsql.antlr.AntlrContext; 14 | 15 | public class CComplexityVisitor implements IParseTreeItemVisitor { 16 | int complexity = 1; 17 | 18 | public int getMeasure() { 19 | return complexity; 20 | } 21 | 22 | private static final Logger LOGGER = Loggers.get(CComplexityVisitor.class); 23 | 24 | @Override 25 | public void apply(final ParseTree tree) { 26 | final Class classz = tree.getClass(); 27 | if (Search_condition_notContext.class.equals(classz)) { 28 | complexity++; 29 | } 30 | 31 | if (Try_catch_statementContext.class.equals(classz)) { 32 | complexity++; 33 | } 34 | 35 | } 36 | 37 | @Override 38 | public void fillContext(SensorContext sensorContext, AntlrContext antrlContext) { 39 | 40 | final InputFile file = antrlContext.getFile(); 41 | synchronized (sensorContext) { 42 | try { 43 | sensorContext.newMeasure().on(file).forMetric(CoreMetrics.COMPLEXITY).withValue(complexity) 44 | .save(); 45 | } catch (final Throwable e) { 46 | LOGGER.warn(format("Unexpected adding complexity measures on file %s", file.absolutePath()), e); 47 | } 48 | } 49 | 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/visitors/ComplexityVisitor.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.visitors; 2 | 3 | import static java.lang.String.format; 4 | 5 | import org.antlr.tsql.TSqlParser.Dml_clauseContext; 6 | import org.antlr.tsql.TSqlParser.Function_callContext; 7 | import org.antlr.tsql.TSqlParser.Join_partContext; 8 | import org.antlr.tsql.TSqlParser.Order_by_expressionContext; 9 | import org.antlr.tsql.TSqlParser.Search_condition_notContext; 10 | import org.antlr.tsql.TSqlParser.Select_list_elemContext; 11 | import org.antlr.tsql.TSqlParser.Sql_unionContext; 12 | import org.antlr.v4.runtime.tree.ParseTree; 13 | import org.sonar.api.batch.fs.InputFile; 14 | import org.sonar.api.batch.sensor.SensorContext; 15 | import org.sonar.api.measures.CoreMetrics; 16 | import org.sonar.api.utils.log.Logger; 17 | import org.sonar.api.utils.log.Loggers; 18 | import org.sonar.plugins.tsql.antlr.AntlrContext; 19 | 20 | public class ComplexityVisitor implements IParseTreeItemVisitor { 21 | int complexity = 0; 22 | 23 | private static final Logger LOGGER = Loggers.get(ComplexityVisitor.class); 24 | 25 | public int getMeasure() { 26 | return complexity; 27 | } 28 | 29 | @Override 30 | public void apply(final ParseTree tree) { 31 | final Class classz = tree.getClass(); 32 | if (Sql_unionContext.class.equals(classz)) { 33 | this.complexity++; 34 | } 35 | if (Function_callContext.class.isAssignableFrom(classz)) { 36 | this.complexity++; 37 | } 38 | if (Join_partContext.class.equals(classz)) { 39 | this.complexity++; 40 | } 41 | if (Order_by_expressionContext.class.equals(classz)) { 42 | this.complexity++; 43 | } 44 | if (Select_list_elemContext.class.equals(classz)) { 45 | this.complexity++; 46 | } 47 | if (Search_condition_notContext.class.equals(classz)) { 48 | this.complexity++; 49 | } 50 | if (Dml_clauseContext.class.equals(classz)) { 51 | this.complexity++; 52 | } 53 | 54 | } 55 | 56 | @Override 57 | public void fillContext(SensorContext sensorContext, AntlrContext antrlContext) { 58 | final InputFile file = antrlContext.getFile(); 59 | synchronized (sensorContext) { 60 | try { 61 | sensorContext.newMeasure().on(file).forMetric(CoreMetrics.COGNITIVE_COMPLEXITY) 62 | .withValue(complexity).save(); 63 | } catch (final Throwable e) { 64 | LOGGER.warn(format("Unexpected adding cognitive complexity measures on file %s", file.absolutePath()), 65 | e); 66 | } 67 | } 68 | 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/visitors/CustomRulesVisitor.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.visitors; 2 | 3 | import java.util.HashMap; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import org.antlr.v4.runtime.tree.ParseTree; 9 | import org.sonar.api.batch.fs.InputFile; 10 | import org.sonar.api.batch.sensor.SensorContext; 11 | import org.sonar.plugins.tsql.antlr.AntlrContext; 12 | import org.sonar.plugins.tsql.antlr.CandidateNode; 13 | import org.sonar.plugins.tsql.antlr.CandidateRule; 14 | import org.sonar.plugins.tsql.antlr.issues.CustomIssuesProvider; 15 | import org.sonar.plugins.tsql.antlr.nodes.ParsedNode; 16 | import org.sonar.plugins.tsql.antlr.nodes.matchers.IMatcher; 17 | import org.sonar.plugins.tsql.antlr.nodes.matchers.NodeNameAndOrClassMatcher; 18 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 19 | import org.sonar.plugins.tsql.checks.custom.RuleMode; 20 | import org.sonar.plugins.tsql.rules.issues.DefaultIssuesFiller; 21 | import org.sonar.plugins.tsql.rules.issues.IIssuesFiller; 22 | import org.sonar.plugins.tsql.rules.issues.TsqlIssue; 23 | 24 | public class CustomRulesVisitor implements IParseTreeItemVisitor { 25 | 26 | private final Map groupedNodes = new HashMap<>(); 27 | private final List singleNodes = new LinkedList<>(); 28 | 29 | private final IMatcher matcher = new NodeNameAndOrClassMatcher(); 30 | private final CandidateRule[] rules; 31 | 32 | private final IIssuesFiller filler = new DefaultIssuesFiller(); 33 | private final CustomIssuesProvider issuesProvider = new CustomIssuesProvider(); 34 | 35 | public CustomRulesVisitor(final CandidateRule... rules) { 36 | this.rules = rules; 37 | } 38 | 39 | @Override 40 | public void apply(final ParseTree tree) { 41 | final ParsedNode parsedNode = new org.sonar.plugins.tsql.antlr.nodes.ParsedNode(tree); 42 | 43 | for (final CandidateRule rule : this.rules) { 44 | 45 | final RuleImplementation ruleImplemention = rule.getRuleImplementation(); 46 | if (matcher.match(ruleImplemention, parsedNode)) { 47 | final CandidateNode node = new CandidateNode(rule, parsedNode); 48 | if (ruleImplemention.getRuleMode() == RuleMode.GROUP) { 49 | final String name = tree.getText(); 50 | groupedNodes.putIfAbsent(name, node); 51 | } else { 52 | singleNodes.add(node); 53 | } 54 | } 55 | 56 | } 57 | 58 | } 59 | 60 | public CandidateNode[] getNodes() { 61 | singleNodes.addAll(groupedNodes.values()); 62 | return singleNodes.toArray(new CandidateNode[0]); 63 | } 64 | 65 | @Override 66 | public void fillContext(SensorContext sensorContext, AntlrContext fillerRequest) { 67 | final InputFile file = fillerRequest.getFile(); 68 | TsqlIssue[] foundIssues = issuesProvider.getIssues(fillerRequest, this.getNodes()); 69 | filler.fill(sensorContext, file, foundIssues); 70 | 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/visitors/CustomTreeVisitor.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.visitors; 2 | 3 | import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; 4 | import org.antlr.v4.runtime.tree.ParseTree; 5 | import org.sonar.api.batch.sensor.SensorContext; 6 | import org.sonar.plugins.tsql.antlr.AntlrContext; 7 | 8 | @SuppressWarnings("rawtypes") 9 | public class CustomTreeVisitor extends AbstractParseTreeVisitor implements IParseTreeItemVisitor { 10 | 11 | private final IParseTreeItemVisitor[] visitors; 12 | 13 | public CustomTreeVisitor(final IParseTreeItemVisitor... visitors) { 14 | this.visitors = visitors; 15 | } 16 | 17 | @Override 18 | public Object visit(final ParseTree tree) { 19 | 20 | final int n = tree.getChildCount(); 21 | 22 | for (int i = 0; i < n; i++) { 23 | final ParseTree c = tree.getChild(i); 24 | visit(c); 25 | } 26 | for (final IParseTreeItemVisitor visitor : this.visitors) { 27 | visitor.apply(tree); 28 | } 29 | 30 | return null; 31 | } 32 | 33 | @Override 34 | public void fillContext(SensorContext context, AntlrContext antlrContext) { 35 | this.apply(antlrContext.getRoot()); 36 | for (final IParseTreeItemVisitor visitor : this.visitors) { 37 | visitor.fillContext(context, antlrContext); 38 | } 39 | } 40 | 41 | @Override 42 | public void apply(ParseTree tree) { 43 | this.visit(tree); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/antlr/visitors/IParseTreeItemVisitor.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.visitors; 2 | 3 | import org.antlr.v4.runtime.tree.ParseTree; 4 | import org.sonar.api.batch.sensor.SensorContext; 5 | import org.sonar.plugins.tsql.antlr.AntlrContext; 6 | 7 | public interface IParseTreeItemVisitor { 8 | void apply(ParseTree tree); 9 | 10 | void fillContext(SensorContext context, AntlrContext antlrContext); 11 | } 12 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/CustomAllChecksProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.checks; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.sonar.api.batch.rule.Severity; 8 | import org.sonar.api.batch.sensor.SensorContext; 9 | import org.sonar.api.config.Configuration; 10 | import org.sonar.api.rules.RuleType; 11 | import org.sonar.api.utils.log.Logger; 12 | import org.sonar.api.utils.log.Loggers; 13 | import org.sonar.plugins.tsql.Constants; 14 | import org.sonar.plugins.tsql.antlr.CandidateRule; 15 | import org.sonar.plugins.tsql.checks.custom.Rule; 16 | import org.sonar.plugins.tsql.checks.custom.SqlRules; 17 | 18 | public class CustomAllChecksProvider { 19 | 20 | private final CustomUserChecksProvider provider = new CustomUserChecksProvider(); 21 | 22 | private final CustomPluginChecks pluginChecksProvider = new CustomPluginChecks(); 23 | private static final Logger LOGGER = Loggers.get(CustomAllChecksProvider.class); 24 | 25 | public CandidateRule[] getChecks(final SensorContext context) { 26 | final Configuration config = context.config(); 27 | final boolean skipCustomRules = config.getBoolean(Constants.PLUGIN_SKIP_CUSTOM_RULES).orElse(false); 28 | final String baseDir = context.fileSystem().baseDir().getAbsolutePath(); 29 | 30 | final String[] paths = config.getStringArray(Constants.PLUGIN_CUSTOM_RULES_PATH); 31 | final String rulesPrefix = config.get(Constants.PLUGIN_CUSTOM_RULES_PREFIX).orElse(".customRules"); 32 | 33 | final List rules = new ArrayList<>(); 34 | 35 | rules.addAll(provider.getRules(baseDir, rulesPrefix, paths).values()); 36 | 37 | if (!skipCustomRules) { 38 | final SqlRules customRules = pluginChecksProvider.getRules(); 39 | rules.add(customRules); 40 | } 41 | 42 | for (final SqlRules sqlRules : rules) { 43 | if (sqlRules.isIsAdhoc()) { 44 | for (final Rule r : sqlRules.getRule()) { 45 | context.newAdHocRule().description(r.getDescription()).engineId(sqlRules.getRepoKey()) 46 | .ruleId(r.getKey()).type(RuleType.valueOf(r.getRuleType())).name(r.getName()) 47 | .severity(Severity.valueOf(r.getSeverity())).save(); 48 | } 49 | } 50 | } 51 | 52 | final SqlRules[] finalRules = rules.toArray(new SqlRules[0]); 53 | 54 | final CandidateRule[] candidateRules = convert(finalRules); 55 | LOGGER.info(String.format("Total %s custom rules repositories with total %s checks", rules.size(), 56 | candidateRules.length)); 57 | return candidateRules; 58 | 59 | } 60 | 61 | private static CandidateRule[] convert(final SqlRules... rules) { 62 | final List convertedRules = new ArrayList<>(); 63 | for (final SqlRules r : rules) { 64 | for (final Rule rule : r.getRule()) { 65 | convertedRules.add(new CandidateRule(r.getRepoKey(), rule, r.isIsAdhoc())); 66 | } 67 | } 68 | return convertedRules.toArray(new CandidateRule[0]); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/CustomPluginChecks.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gretard/sonar-tsql-plugin/aadb5598bbb183c12df997ee9f3e053f962ce0f7/sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/CustomPluginChecks.java -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/CustomUserChecksProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.checks; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.nio.file.Files; 9 | import java.nio.file.Path; 10 | import java.util.HashMap; 11 | import java.util.LinkedList; 12 | import java.util.List; 13 | import java.util.Map; 14 | import java.util.stream.Stream; 15 | 16 | import javax.xml.bind.JAXBContext; 17 | import javax.xml.bind.JAXBException; 18 | import javax.xml.bind.Unmarshaller; 19 | 20 | import org.sonar.api.utils.log.Logger; 21 | import org.sonar.api.utils.log.Loggers; 22 | import org.sonar.plugins.tsql.checks.custom.SqlRules; 23 | 24 | public class CustomUserChecksProvider { 25 | private static final Logger LOGGER = Loggers.get(CustomUserChecksProvider.class); 26 | 27 | public Map getRules(final String baseDir, final String prefix, final String... paths) { 28 | 29 | final HashMap rulesRepositories = new HashMap<>(); 30 | 31 | final List updatedPaths = new LinkedList<>(); 32 | for (final String path : paths) { 33 | File f = new File(path); 34 | if (baseDir != null && !f.isAbsolute()) { 35 | f = new File(baseDir, path); 36 | } 37 | try (final Stream stream = Files.walk(f.toPath())) { 38 | stream.filter(x -> x.toFile().isFile() && x.toString().contains(prefix)) 39 | .forEach(x -> updatedPaths.add(x.toFile().getAbsolutePath())); 40 | } catch (IOException e) { 41 | LOGGER.info(String.format("Unexpected error ocurred while reading: %s", f.getAbsolutePath()), e); 42 | } 43 | } 44 | 45 | for (final String path : updatedPaths) { 46 | 47 | try (final InputStream file = new FileInputStream(path)) { 48 | final JAXBContext jaxbContext = JAXBContext.newInstance(SqlRules.class); 49 | final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); 50 | final SqlRules rules = (SqlRules) jaxbUnmarshaller.unmarshal(file); 51 | rulesRepositories.put(path, rules); 52 | LOGGER.info(String.format("Read %s rules ok at: %s", rules.getRule().size(), path)); 53 | } catch (final FileNotFoundException e) { 54 | LOGGER.info("Custom rule file not found at: " + path); 55 | } catch (final JAXBException e) { 56 | LOGGER.info("Was not able to read custom rule file not found at: " + path); 57 | } catch (final IOException e) { 58 | LOGGER.info("Was not able to close custom rule file at: " + path); 59 | } 60 | } 61 | 62 | return rulesRepositories; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/custom/ChildrenRules.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.12.22 at 03:20:06 PM EET 6 | // 7 | 8 | 9 | package org.sonar.plugins.tsql.checks.custom; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import javax.xml.bind.annotation.XmlAccessType; 14 | import javax.xml.bind.annotation.XmlAccessorType; 15 | import javax.xml.bind.annotation.XmlRootElement; 16 | import javax.xml.bind.annotation.XmlType; 17 | 18 | 19 | /** 20 | *

Java class for anonymous complex type. 21 | * 22 | *

The following schema fragment specifies the expected content contained within this class. 23 | * 24 | *

25 |  * <complexType>
26 |  *   <complexContent>
27 |  *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
28 |  *       <sequence>
29 |  *         <element ref="{}ruleImplementation" maxOccurs="unbounded" minOccurs="0"/>
30 |  *       </sequence>
31 |  *     </restriction>
32 |  *   </complexContent>
33 |  * </complexType>
34 |  * 
35 | * 36 | * 37 | */ 38 | @XmlAccessorType(XmlAccessType.FIELD) 39 | @XmlType(name = "", propOrder = { 40 | "ruleImplementation" 41 | }) 42 | @XmlRootElement(name = "childrenRules") 43 | public class ChildrenRules { 44 | 45 | protected List ruleImplementation; 46 | 47 | /** 48 | * Gets the value of the ruleImplementation property. 49 | * 50 | *

51 | * This accessor method returns a reference to the live list, 52 | * not a snapshot. Therefore any modification you make to the 53 | * returned list will be present inside the JAXB object. 54 | * This is why there is not a set method for the ruleImplementation property. 55 | * 56 | *

57 | * For example, to add a new item, do as follows: 58 | *

59 |      *    getRuleImplementation().add(newItem);
60 |      * 
61 | * 62 | * 63 | *

64 | * Objects of the following type(s) are allowed in the list 65 | * {@link RuleImplementation } 66 | * 67 | * 68 | */ 69 | public List getRuleImplementation() { 70 | if (ruleImplementation == null) { 71 | ruleImplementation = new ArrayList(); 72 | } 73 | return this.ruleImplementation; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/custom/CompliantRulesCodeExamples.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.12.22 at 03:20:06 PM EET 6 | // 7 | 8 | 9 | package org.sonar.plugins.tsql.checks.custom; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import javax.xml.bind.annotation.XmlAccessType; 14 | import javax.xml.bind.annotation.XmlAccessorType; 15 | import javax.xml.bind.annotation.XmlRootElement; 16 | import javax.xml.bind.annotation.XmlType; 17 | 18 | 19 | /** 20 | *

Java class for anonymous complex type. 21 | * 22 | *

The following schema fragment specifies the expected content contained within this class. 23 | * 24 | *

25 |  * <complexType>
26 |  *   <complexContent>
27 |  *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
28 |  *       <sequence>
29 |  *         <element ref="{}ruleCodeExample" maxOccurs="unbounded" minOccurs="0"/>
30 |  *       </sequence>
31 |  *     </restriction>
32 |  *   </complexContent>
33 |  * </complexType>
34 |  * 
35 | * 36 | * 37 | */ 38 | @XmlAccessorType(XmlAccessType.FIELD) 39 | @XmlType(name = "", propOrder = { 40 | "ruleCodeExample" 41 | }) 42 | @XmlRootElement(name = "compliantRulesCodeExamples") 43 | public class CompliantRulesCodeExamples { 44 | 45 | protected List ruleCodeExample; 46 | 47 | /** 48 | * Gets the value of the ruleCodeExample property. 49 | * 50 | *

51 | * This accessor method returns a reference to the live list, 52 | * not a snapshot. Therefore any modification you make to the 53 | * returned list will be present inside the JAXB object. 54 | * This is why there is not a set method for the ruleCodeExample property. 55 | * 56 | *

57 | * For example, to add a new item, do as follows: 58 | *

59 |      *    getRuleCodeExample().add(newItem);
60 |      * 
61 | * 62 | * 63 | *

64 | * Objects of the following type(s) are allowed in the list 65 | * {@link String } 66 | * 67 | * 68 | */ 69 | public List getRuleCodeExample() { 70 | if (ruleCodeExample == null) { 71 | ruleCodeExample = new ArrayList(); 72 | } 73 | return this.ruleCodeExample; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/custom/Names.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.12.22 at 03:20:06 PM EET 6 | // 7 | 8 | 9 | package org.sonar.plugins.tsql.checks.custom; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import javax.xml.bind.annotation.XmlAccessType; 14 | import javax.xml.bind.annotation.XmlAccessorType; 15 | import javax.xml.bind.annotation.XmlRootElement; 16 | import javax.xml.bind.annotation.XmlType; 17 | 18 | 19 | /** 20 | *

Java class for anonymous complex type. 21 | * 22 | *

The following schema fragment specifies the expected content contained within this class. 23 | * 24 | *

25 |  * <complexType>
26 |  *   <complexContent>
27 |  *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
28 |  *       <sequence>
29 |  *         <element ref="{}textItem" maxOccurs="unbounded" minOccurs="0"/>
30 |  *       </sequence>
31 |  *     </restriction>
32 |  *   </complexContent>
33 |  * </complexType>
34 |  * 
35 | * 36 | * 37 | */ 38 | @XmlAccessorType(XmlAccessType.FIELD) 39 | @XmlType(name = "", propOrder = { 40 | "textItem" 41 | }) 42 | @XmlRootElement(name = "names") 43 | public class Names { 44 | 45 | protected List textItem; 46 | 47 | /** 48 | * Gets the value of the textItem property. 49 | * 50 | *

51 | * This accessor method returns a reference to the live list, 52 | * not a snapshot. Therefore any modification you make to the 53 | * returned list will be present inside the JAXB object. 54 | * This is why there is not a set method for the textItem property. 55 | * 56 | *

57 | * For example, to add a new item, do as follows: 58 | *

59 |      *    getTextItem().add(newItem);
60 |      * 
61 | * 62 | * 63 | *

64 | * Objects of the following type(s) are allowed in the list 65 | * {@link String } 66 | * 67 | * 68 | */ 69 | public List getTextItem() { 70 | if (textItem == null) { 71 | textItem = new ArrayList(); 72 | } 73 | return this.textItem; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/custom/ParentRules.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.12.22 at 03:20:06 PM EET 6 | // 7 | 8 | 9 | package org.sonar.plugins.tsql.checks.custom; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import javax.xml.bind.annotation.XmlAccessType; 14 | import javax.xml.bind.annotation.XmlAccessorType; 15 | import javax.xml.bind.annotation.XmlRootElement; 16 | import javax.xml.bind.annotation.XmlType; 17 | 18 | 19 | /** 20 | *

Java class for anonymous complex type. 21 | * 22 | *

The following schema fragment specifies the expected content contained within this class. 23 | * 24 | *

25 |  * <complexType>
26 |  *   <complexContent>
27 |  *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
28 |  *       <sequence>
29 |  *         <element ref="{}ruleImplementation" maxOccurs="unbounded" minOccurs="0"/>
30 |  *       </sequence>
31 |  *     </restriction>
32 |  *   </complexContent>
33 |  * </complexType>
34 |  * 
35 | * 36 | * 37 | */ 38 | @XmlAccessorType(XmlAccessType.FIELD) 39 | @XmlType(name = "", propOrder = { 40 | "ruleImplementation" 41 | }) 42 | @XmlRootElement(name = "parentRules") 43 | public class ParentRules { 44 | 45 | protected List ruleImplementation; 46 | 47 | /** 48 | * Gets the value of the ruleImplementation property. 49 | * 50 | *

51 | * This accessor method returns a reference to the live list, 52 | * not a snapshot. Therefore any modification you make to the 53 | * returned list will be present inside the JAXB object. 54 | * This is why there is not a set method for the ruleImplementation property. 55 | * 56 | *

57 | * For example, to add a new item, do as follows: 58 | *

59 |      *    getRuleImplementation().add(newItem);
60 |      * 
61 | * 62 | * 63 | *

64 | * Objects of the following type(s) are allowed in the list 65 | * {@link RuleImplementation } 66 | * 67 | * 68 | */ 69 | public List getRuleImplementation() { 70 | if (ruleImplementation == null) { 71 | ruleImplementation = new ArrayList(); 72 | } 73 | return this.ruleImplementation; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/custom/RuleDistanceIndexMatchType.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.12.22 at 03:20:06 PM EET 6 | // 7 | 8 | 9 | package org.sonar.plugins.tsql.checks.custom; 10 | 11 | import javax.xml.bind.annotation.XmlEnum; 12 | import javax.xml.bind.annotation.XmlEnumValue; 13 | import javax.xml.bind.annotation.XmlType; 14 | 15 | 16 | /** 17 | *

Java class for ruleDistanceIndexMatchType. 18 | * 19 | *

The following schema fragment specifies the expected content contained within this class. 20 | *

21 | *

22 |  * <simpleType name="ruleDistanceIndexMatchType">
23 |  *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
24 |  *     <enumeration value="Default"/>
25 |  *     <enumeration value="More"/>
26 |  *     <enumeration value="Less"/>
27 |  *     <enumeration value="Equals"/>
28 |  *   </restriction>
29 |  * </simpleType>
30 |  * 
31 | * 32 | */ 33 | @XmlType(name = "ruleDistanceIndexMatchType") 34 | @XmlEnum 35 | public enum RuleDistanceIndexMatchType { 36 | 37 | @XmlEnumValue("Default") 38 | DEFAULT("Default"), 39 | @XmlEnumValue("More") 40 | MORE("More"), 41 | @XmlEnumValue("Less") 42 | LESS("Less"), 43 | @XmlEnumValue("Equals") 44 | EQUALS("Equals"); 45 | private final String value; 46 | 47 | RuleDistanceIndexMatchType(String v) { 48 | value = v; 49 | } 50 | 51 | public String value() { 52 | return value; 53 | } 54 | 55 | public static RuleDistanceIndexMatchType fromValue(String v) { 56 | for (RuleDistanceIndexMatchType c: RuleDistanceIndexMatchType.values()) { 57 | if (c.value.equals(v)) { 58 | return c; 59 | } 60 | } 61 | throw new IllegalArgumentException(v); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/custom/RuleMatchType.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.12.22 at 03:20:06 PM EET 6 | // 7 | 8 | 9 | package org.sonar.plugins.tsql.checks.custom; 10 | 11 | import javax.xml.bind.annotation.XmlEnum; 12 | import javax.xml.bind.annotation.XmlEnumValue; 13 | import javax.xml.bind.annotation.XmlType; 14 | 15 | 16 | /** 17 | *

Java class for ruleMatchType. 18 | * 19 | *

The following schema fragment specifies the expected content contained within this class. 20 | *

21 | *

22 |  * <simpleType name="ruleMatchType">
23 |  *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
24 |  *     <enumeration value="Default"/>
25 |  *     <enumeration value="Full"/>
26 |  *     <enumeration value="TextOnly"/>
27 |  *     <enumeration value="TextAndClass"/>
28 |  *     <enumeration value="ClassOnly"/>
29 |  *     <enumeration value="Strict"/>
30 |  *   </restriction>
31 |  * </simpleType>
32 |  * 
33 | * 34 | */ 35 | @XmlType(name = "ruleMatchType") 36 | @XmlEnum 37 | public enum RuleMatchType { 38 | 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 | for (RuleMatchType c: RuleMatchType.values()) { 63 | if (c.value.equals(v)) { 64 | return c; 65 | } 66 | } 67 | throw new IllegalArgumentException(v); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/custom/RuleMode.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.12.22 at 03:20:06 PM EET 6 | // 7 | 8 | 9 | package org.sonar.plugins.tsql.checks.custom; 10 | 11 | import javax.xml.bind.annotation.XmlEnum; 12 | import javax.xml.bind.annotation.XmlEnumValue; 13 | import javax.xml.bind.annotation.XmlType; 14 | 15 | 16 | /** 17 | *

Java class for ruleMode. 18 | * 19 | *

The following schema fragment specifies the expected content contained within this class. 20 | *

21 | *

22 |  * <simpleType name="ruleMode">
23 |  *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
24 |  *     <enumeration value="Default"/>
25 |  *     <enumeration value="Group"/>
26 |  *     <enumeration value="Single"/>
27 |  *   </restriction>
28 |  * </simpleType>
29 |  * 
30 | * 31 | */ 32 | @XmlType(name = "ruleMode") 33 | @XmlEnum 34 | public enum RuleMode { 35 | 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 | for (RuleMode c: RuleMode.values()) { 54 | if (c.value.equals(v)) { 55 | return c; 56 | } 57 | } 58 | throw new IllegalArgumentException(v); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/custom/RuleResultType.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.12.22 at 03:20:06 PM EET 6 | // 7 | 8 | 9 | package org.sonar.plugins.tsql.checks.custom; 10 | 11 | import javax.xml.bind.annotation.XmlEnum; 12 | import javax.xml.bind.annotation.XmlEnumValue; 13 | import javax.xml.bind.annotation.XmlType; 14 | 15 | 16 | /** 17 | *

Java class for ruleResultType. 18 | * 19 | *

The following schema fragment specifies the expected content contained within this class. 20 | *

21 | *

22 |  * <simpleType name="ruleResultType">
23 |  *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
24 |  *     <enumeration value="Default"/>
25 |  *     <enumeration value="FailIfFound"/>
26 |  *     <enumeration value="FailIfNotFound"/>
27 |  *     <enumeration value="FailIfLessFound"/>
28 |  *     <enumeration value="FailIfMoreFound"/>
29 |  *     <enumeration value="SkipIfFound"/>
30 |  *     <enumeration value="SkipIfNotFound"/>
31 |  *   </restriction>
32 |  * </simpleType>
33 |  * 
34 | * 35 | */ 36 | @XmlType(name = "ruleResultType") 37 | @XmlEnum 38 | public enum RuleResultType { 39 | 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 | @XmlEnumValue("SkipIfNotFound") 53 | SKIP_IF_NOT_FOUND("SkipIfNotFound"); 54 | private final String value; 55 | 56 | RuleResultType(String v) { 57 | value = v; 58 | } 59 | 60 | public String value() { 61 | return value; 62 | } 63 | 64 | public static RuleResultType fromValue(String v) { 65 | for (RuleResultType c: RuleResultType.values()) { 66 | if (c.value.equals(v)) { 67 | return c; 68 | } 69 | } 70 | throw new IllegalArgumentException(v); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/custom/SiblingsRules.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.12.22 at 03:20:06 PM EET 6 | // 7 | 8 | 9 | package org.sonar.plugins.tsql.checks.custom; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import javax.xml.bind.annotation.XmlAccessType; 14 | import javax.xml.bind.annotation.XmlAccessorType; 15 | import javax.xml.bind.annotation.XmlRootElement; 16 | import javax.xml.bind.annotation.XmlType; 17 | 18 | 19 | /** 20 | *

Java class for anonymous complex type. 21 | * 22 | *

The following schema fragment specifies the expected content contained within this class. 23 | * 24 | *

25 |  * <complexType>
26 |  *   <complexContent>
27 |  *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
28 |  *       <sequence>
29 |  *         <element ref="{}ruleImplementation" maxOccurs="unbounded" minOccurs="0"/>
30 |  *       </sequence>
31 |  *     </restriction>
32 |  *   </complexContent>
33 |  * </complexType>
34 |  * 
35 | * 36 | * 37 | */ 38 | @XmlAccessorType(XmlAccessType.FIELD) 39 | @XmlType(name = "", propOrder = { 40 | "ruleImplementation" 41 | }) 42 | @XmlRootElement(name = "siblingsRules") 43 | public class SiblingsRules { 44 | 45 | protected List ruleImplementation; 46 | 47 | /** 48 | * Gets the value of the ruleImplementation property. 49 | * 50 | *

51 | * This accessor method returns a reference to the live list, 52 | * not a snapshot. Therefore any modification you make to the 53 | * returned list will be present inside the JAXB object. 54 | * This is why there is not a set method for the ruleImplementation property. 55 | * 56 | *

57 | * For example, to add a new item, do as follows: 58 | *

59 |      *    getRuleImplementation().add(newItem);
60 |      * 
61 | * 62 | * 63 | *

64 | * Objects of the following type(s) are allowed in the list 65 | * {@link RuleImplementation } 66 | * 67 | * 68 | */ 69 | public List getRuleImplementation() { 70 | if (ruleImplementation == null) { 71 | ruleImplementation = new ArrayList(); 72 | } 73 | return this.ruleImplementation; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/custom/TextCheckType.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.12.22 at 03:20:06 PM EET 6 | // 7 | 8 | 9 | package org.sonar.plugins.tsql.checks.custom; 10 | 11 | import javax.xml.bind.annotation.XmlEnum; 12 | import javax.xml.bind.annotation.XmlEnumValue; 13 | import javax.xml.bind.annotation.XmlType; 14 | 15 | 16 | /** 17 | *

Java class for textCheckType. 18 | * 19 | *

The following schema fragment specifies the expected content contained within this class. 20 | *

21 | *

22 |  * <simpleType name="textCheckType">
23 |  *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
24 |  *     <enumeration value="Default"/>
25 |  *     <enumeration value="Contains"/>
26 |  *     <enumeration value="Regexp"/>
27 |  *     <enumeration value="Strict"/>
28 |  *   </restriction>
29 |  * </simpleType>
30 |  * 
31 | * 32 | */ 33 | @XmlType(name = "textCheckType") 34 | @XmlEnum 35 | public enum TextCheckType { 36 | 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 | for (TextCheckType c: TextCheckType.values()) { 57 | if (c.value.equals(v)) { 58 | return c; 59 | } 60 | } 61 | throw new IllegalArgumentException(v); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/custom/TextToFind.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.12.22 at 03:20:06 PM EET 6 | // 7 | 8 | 9 | package org.sonar.plugins.tsql.checks.custom; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import javax.xml.bind.annotation.XmlAccessType; 14 | import javax.xml.bind.annotation.XmlAccessorType; 15 | import javax.xml.bind.annotation.XmlRootElement; 16 | import javax.xml.bind.annotation.XmlType; 17 | 18 | 19 | /** 20 | *

Java class for anonymous complex type. 21 | * 22 | *

The following schema fragment specifies the expected content contained within this class. 23 | * 24 | *

25 |  * <complexType>
26 |  *   <complexContent>
27 |  *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
28 |  *       <sequence>
29 |  *         <element ref="{}textItem" maxOccurs="unbounded" minOccurs="0"/>
30 |  *       </sequence>
31 |  *     </restriction>
32 |  *   </complexContent>
33 |  * </complexType>
34 |  * 
35 | * 36 | * 37 | */ 38 | @XmlAccessorType(XmlAccessType.FIELD) 39 | @XmlType(name = "", propOrder = { 40 | "textItem" 41 | }) 42 | @XmlRootElement(name = "textToFind") 43 | public class TextToFind { 44 | 45 | protected List textItem; 46 | 47 | /** 48 | * Gets the value of the textItem property. 49 | * 50 | *

51 | * This accessor method returns a reference to the live list, 52 | * not a snapshot. Therefore any modification you make to the 53 | * returned list will be present inside the JAXB object. 54 | * This is why there is not a set method for the textItem property. 55 | * 56 | *

57 | * For example, to add a new item, do as follows: 58 | *

59 |      *    getTextItem().add(newItem);
60 |      * 
61 | * 62 | * 63 | *

64 | * Objects of the following type(s) are allowed in the list 65 | * {@link String } 66 | * 67 | * 68 | */ 69 | public List getTextItem() { 70 | if (textItem == null) { 71 | textItem = new ArrayList(); 72 | } 73 | return this.textItem; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/custom/UsesRules.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.12.22 at 03:20:06 PM EET 6 | // 7 | 8 | 9 | package org.sonar.plugins.tsql.checks.custom; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import javax.xml.bind.annotation.XmlAccessType; 14 | import javax.xml.bind.annotation.XmlAccessorType; 15 | import javax.xml.bind.annotation.XmlRootElement; 16 | import javax.xml.bind.annotation.XmlType; 17 | 18 | 19 | /** 20 | *

Java class for anonymous complex type. 21 | * 22 | *

The following schema fragment specifies the expected content contained within this class. 23 | * 24 | *

25 |  * <complexType>
26 |  *   <complexContent>
27 |  *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
28 |  *       <sequence>
29 |  *         <element ref="{}ruleImplementation" maxOccurs="unbounded" minOccurs="0"/>
30 |  *       </sequence>
31 |  *     </restriction>
32 |  *   </complexContent>
33 |  * </complexType>
34 |  * 
35 | * 36 | * 37 | */ 38 | @XmlAccessorType(XmlAccessType.FIELD) 39 | @XmlType(name = "", propOrder = { 40 | "ruleImplementation" 41 | }) 42 | @XmlRootElement(name = "usesRules") 43 | public class UsesRules { 44 | 45 | protected List ruleImplementation; 46 | 47 | /** 48 | * Gets the value of the ruleImplementation property. 49 | * 50 | *

51 | * This accessor method returns a reference to the live list, 52 | * not a snapshot. Therefore any modification you make to the 53 | * returned list will be present inside the JAXB object. 54 | * This is why there is not a set method for the ruleImplementation property. 55 | * 56 | *

57 | * For example, to add a new item, do as follows: 58 | *

59 |      *    getRuleImplementation().add(newItem);
60 |      * 
61 | * 62 | * 63 | *

64 | * Objects of the following type(s) are allowed in the list 65 | * {@link RuleImplementation } 66 | * 67 | * 68 | */ 69 | public List getRuleImplementation() { 70 | if (ruleImplementation == null) { 71 | ruleImplementation = new ArrayList(); 72 | } 73 | return this.ruleImplementation; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/checks/custom/ViolatingRulesCodeExamples.java: -------------------------------------------------------------------------------- 1 | // 2 | // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 3 | // See http://java.sun.com/xml/jaxb 4 | // Any modifications to this file will be lost upon recompilation of the source schema. 5 | // Generated on: 2018.12.22 at 03:20:06 PM EET 6 | // 7 | 8 | 9 | package org.sonar.plugins.tsql.checks.custom; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import javax.xml.bind.annotation.XmlAccessType; 14 | import javax.xml.bind.annotation.XmlAccessorType; 15 | import javax.xml.bind.annotation.XmlRootElement; 16 | import javax.xml.bind.annotation.XmlType; 17 | 18 | 19 | /** 20 | *

Java class for anonymous complex type. 21 | * 22 | *

The following schema fragment specifies the expected content contained within this class. 23 | * 24 | *

25 |  * <complexType>
26 |  *   <complexContent>
27 |  *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
28 |  *       <sequence>
29 |  *         <element ref="{}ruleCodeExample" maxOccurs="unbounded" minOccurs="0"/>
30 |  *       </sequence>
31 |  *     </restriction>
32 |  *   </complexContent>
33 |  * </complexType>
34 |  * 
35 | * 36 | * 37 | */ 38 | @XmlAccessorType(XmlAccessType.FIELD) 39 | @XmlType(name = "", propOrder = { 40 | "ruleCodeExample" 41 | }) 42 | @XmlRootElement(name = "violatingRulesCodeExamples") 43 | public class ViolatingRulesCodeExamples { 44 | 45 | protected List ruleCodeExample; 46 | 47 | /** 48 | * Gets the value of the ruleCodeExample property. 49 | * 50 | *

51 | * This accessor method returns a reference to the live list, 52 | * not a snapshot. Therefore any modification you make to the 53 | * returned list will be present inside the JAXB object. 54 | * This is why there is not a set method for the ruleCodeExample property. 55 | * 56 | *

57 | * For example, to add a new item, do as follows: 58 | *

59 |      *    getRuleCodeExample().add(newItem);
60 |      * 
61 | * 62 | * 63 | *

64 | * Objects of the following type(s) are allowed in the list 65 | * {@link String } 66 | * 67 | * 68 | */ 69 | public List getRuleCodeExample() { 70 | if (ruleCodeExample == null) { 71 | ruleCodeExample = new ArrayList(); 72 | } 73 | return this.ruleCodeExample; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/coverage/CoveredLinesReport.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.coverage; 2 | 3 | public class CoveredLinesReport { 4 | 5 | private final String file; 6 | 7 | private final LineInfo[] hitLines; 8 | 9 | public CoveredLinesReport(String file, LineInfo... infos) { 10 | this.file = file; 11 | this.hitLines = infos; 12 | } 13 | 14 | public String getFile() { 15 | return file; 16 | } 17 | 18 | public LineInfo[] getHitLines() { 19 | return hitLines; 20 | } 21 | 22 | public static class LineInfo { 23 | private final int line; 24 | private final int hitsCount; 25 | 26 | public LineInfo(final int line, final int hits) { 27 | this.line = line; 28 | this.hitsCount = hits; 29 | } 30 | 31 | public int getLine() { 32 | return line; 33 | } 34 | 35 | public int getHitsCount() { 36 | return hitsCount; 37 | } 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/coverage/FileNamesMatcher.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.coverage; 2 | 3 | import java.util.LinkedList; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Map.Entry; 7 | 8 | import org.apache.commons.io.FilenameUtils; 9 | 10 | public class FileNamesMatcher { 11 | private final NameNormalizer nameNormalizer = new NameNormalizer(); 12 | 13 | public CoveredLinesReport[] match(String fileName, String parentDirName, Map coverage) { 14 | final String name = FilenameUtils.removeExtension(fileName); 15 | final String normalizedName = nameNormalizer.normalize(name); 16 | String schema = nameNormalizer.normalize(parentDirName); 17 | String objName = normalizedName; 18 | 19 | if (normalizedName.contains(".")) { 20 | String[] names = name.split("\\."); 21 | objName = names[names.length-1]; 22 | schema = names[names.length-2]; 23 | } 24 | List possibleMatches = new LinkedList(); 25 | for (Entry info : coverage.entrySet()) { 26 | if (info.getKey().equals(normalizedName)) { 27 | possibleMatches.add(info.getValue()); 28 | break; 29 | } 30 | if (info.getKey().equals(schema+"."+objName)) { 31 | possibleMatches.add(info.getValue()); 32 | break; 33 | } 34 | if (info.getKey().contains(objName)) { 35 | possibleMatches.add(info.getValue()); 36 | } 37 | 38 | } 39 | return possibleMatches.toArray(new CoveredLinesReport[0]); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/coverage/ICoveragProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.coverage; 2 | 3 | import java.util.Map; 4 | 5 | public interface ICoveragProvider { 6 | Map getHitLines(); 7 | } 8 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/coverage/NameNormalizer.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.coverage; 2 | 3 | public class NameNormalizer { 4 | public String normalize(String name) { 5 | if (name == null) { 6 | return ""; 7 | } 8 | return name.replace("[", "").replace("]", "").replace(" ", "").toLowerCase(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/languages/TSQLLanguage.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.languages; 2 | 3 | import org.sonar.api.config.Settings; 4 | import org.sonar.api.resources.AbstractLanguage; 5 | import org.sonar.plugins.tsql.Constants; 6 | 7 | public final class TSQLLanguage extends AbstractLanguage { 8 | 9 | public static final String NAME = "T-SQL"; 10 | 11 | public static final String KEY = "tsql"; 12 | 13 | public static final String[] DEFAULT_FILE_SUFFIXES = new String[] { ".sql" }; 14 | 15 | private final Settings settings; 16 | 17 | public TSQLLanguage(final Settings settings) { 18 | super(KEY, NAME); 19 | this.settings = settings; 20 | 21 | } 22 | 23 | public String[] getFileSuffixes() { 24 | final String[] suffixes = settings.getStringArray(Constants.PLUGIN_SUFFIXES); 25 | if (suffixes == null || suffixes.length == 0) { 26 | return DEFAULT_FILE_SUFFIXES; 27 | } 28 | return suffixes; 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/languages/keywords/IKeywordsProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.languages.keywords; 2 | 3 | public interface IKeywordsProvider { 4 | boolean isKeyword(final String name); 5 | } 6 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/languages/keywords/KeywordsProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.languages.keywords; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStream; 5 | import java.io.InputStreamReader; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.sonar.api.utils.log.Logger; 11 | import org.sonar.api.utils.log.Loggers; 12 | import org.sonar.plugins.tsql.sensors.CustomChecksSensor; 13 | 14 | public class KeywordsProvider implements IKeywordsProvider { 15 | 16 | private static final Logger LOGGER = Loggers.get(CustomChecksSensor.class); 17 | 18 | private final List keywords = new ArrayList(); 19 | 20 | public KeywordsProvider() { 21 | this("/tsql.keywords", "/tsql.odbc.keywords"); 22 | } 23 | 24 | public KeywordsProvider(final String... files) { 25 | for (final String file : files) { 26 | init(file); 27 | } 28 | } 29 | 30 | private void init(final String file) { 31 | try { 32 | final InputStream stream = this.getClass().getResourceAsStream(file); 33 | 34 | final BufferedReader br = new BufferedReader(new InputStreamReader(stream)); 35 | 36 | for (String line; (line = br.readLine()) != null;) { 37 | if (!StringUtils.isEmpty(line)) { 38 | final String keyword = line.toUpperCase().trim(); 39 | if (!this.keywords.contains(keyword)) { 40 | this.keywords.add(keyword); 41 | } 42 | 43 | } 44 | } 45 | } catch (final Throwable e) { 46 | LOGGER.warn(String.format("Error reading keywords file: %s", file), e); 47 | } 48 | 49 | } 50 | 51 | public boolean isKeyword(final String name) { 52 | return this.keywords.contains(name); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/lines/SourceLine.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.lines; 2 | 3 | public final class SourceLine { 4 | 5 | private final int count; 6 | private final int start; 7 | private final int end; 8 | private final int line; 9 | 10 | public SourceLine(final int line, final int count, final int start, final int end) { 11 | this.line = line; 12 | this.count = count; 13 | this.start = start; 14 | this.end = end; 15 | 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | return "SourceLine [line=" + line + ", count=" + count + ", start=" + start + ", end=" + end + "]"; 21 | } 22 | 23 | public int getLine() { 24 | return line; 25 | } 26 | 27 | public int getCount() { 28 | return count; 29 | } 30 | 31 | public int getEnd() { 32 | return end; 33 | } 34 | 35 | public int getStart() { 36 | return start; 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/lines/SourceLinesProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.lines; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStream; 5 | import java.io.InputStreamReader; 6 | import java.nio.charset.Charset; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import org.apache.commons.io.input.BOMInputStream; 11 | import org.sonar.api.utils.log.Logger; 12 | import org.sonar.api.utils.log.Loggers; 13 | 14 | public class SourceLinesProvider { 15 | private static final Logger LOGGER = Loggers.get(SourceLinesProvider.class); 16 | 17 | public SourceLine[] getLines(final InputStream inputStream, final Charset charset) { 18 | if (inputStream == null) { 19 | return new SourceLine[0]; 20 | } 21 | final List sourceLines = new ArrayList<>(); 22 | 23 | try (final BufferedReader bufferedReader = new BufferedReader( 24 | new InputStreamReader(new BOMInputStream(inputStream, false), charset))) { 25 | int totalLines = 1; 26 | int global = 0; 27 | int count = 0; 28 | 29 | int currentChar; 30 | while ((currentChar = bufferedReader.read()) != -1) { 31 | 32 | global++; 33 | count++; 34 | if (currentChar == 10) { 35 | sourceLines.add(new SourceLine(totalLines, count, global - count, global)); 36 | totalLines++; 37 | count = 0; 38 | } 39 | 40 | } 41 | sourceLines.add(new SourceLine(totalLines, count, global - count, global)); 42 | } catch (final Throwable e) { 43 | LOGGER.warn("Error occured reading file", e); 44 | } 45 | 46 | return sourceLines.toArray(new SourceLine[0]); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/predicates/AbsolutePathCaseInsensitivePredicate.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.predicates; 2 | 3 | import org.sonar.api.batch.fs.FilePredicate; 4 | import org.sonar.api.batch.fs.InputFile; 5 | 6 | public class AbsolutePathCaseInsensitivePredicate implements FilePredicate { 7 | 8 | private final String path; 9 | 10 | public AbsolutePathCaseInsensitivePredicate(final String path) { 11 | this.path = path.replace('\\', '/'); 12 | } 13 | 14 | @Override 15 | public boolean apply(final InputFile inputFile) { 16 | return this.path.equalsIgnoreCase(inputFile.absolutePath().replace('\\', '/')); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/definitions/BaseRulesDefinition.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.definitions; 2 | 3 | import java.io.InputStream; 4 | import java.nio.charset.StandardCharsets; 5 | 6 | import org.sonar.api.server.rule.RulesDefinition; 7 | import org.sonar.api.server.rule.RulesDefinitionXmlLoader; 8 | import org.sonar.plugins.tsql.languages.TSQLLanguage; 9 | 10 | public abstract class BaseRulesDefinition implements RulesDefinition { 11 | private final String rulesPath; 12 | private final String repositoryName; 13 | private final String repositoryKey; 14 | 15 | public BaseRulesDefinition(String repositoryKey, String repositoryName, String rulesPath) { 16 | this.repositoryKey = repositoryKey; 17 | this.repositoryName = repositoryName; 18 | this.rulesPath = rulesPath; 19 | 20 | } 21 | 22 | private void defineRulesForLanguage(final Context context) { 23 | final NewRepository repository = context.createRepository(this.repositoryKey, TSQLLanguage.KEY) 24 | .setName(this.repositoryName); 25 | 26 | final InputStream rulesXml = this.getClass().getResourceAsStream(this.rulesPath); 27 | if (rulesXml != null) { 28 | final RulesDefinitionXmlLoader rulesLoader = new RulesDefinitionXmlLoader(); 29 | rulesLoader.load(repository, rulesXml, StandardCharsets.UTF_8.name()); 30 | } 31 | 32 | repository.done(); 33 | } 34 | 35 | @Override 36 | public void define(final Context context) { 37 | defineRulesForLanguage(context); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/definitions/CodeGuardRulesDefinition.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.definitions; 2 | 3 | import org.sonar.plugins.tsql.Constants; 4 | 5 | public final class CodeGuardRulesDefinition extends BaseRulesDefinition { 6 | 7 | public CodeGuardRulesDefinition() { 8 | super(Constants.CG_REPO_KEY, Constants.CG_REPO_NAME, Constants.CG_RULES_FILE); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/definitions/CustomUserChecksRulesDefinition.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.definitions; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.nio.charset.StandardCharsets; 8 | import java.util.Map; 9 | 10 | import org.sonar.api.config.Settings; 11 | import org.sonar.api.server.rule.RulesDefinition; 12 | import org.sonar.api.server.rule.RulesDefinitionXmlLoader; 13 | import org.sonar.api.utils.log.Logger; 14 | import org.sonar.api.utils.log.Loggers; 15 | import org.sonar.plugins.tsql.Constants; 16 | import org.sonar.plugins.tsql.checks.CustomUserChecksProvider; 17 | import org.sonar.plugins.tsql.checks.custom.SqlRules; 18 | import org.sonar.plugins.tsql.languages.TSQLLanguage; 19 | 20 | public class CustomUserChecksRulesDefinition implements RulesDefinition { 21 | 22 | private final Settings settings; 23 | private final CustomUserChecksProvider provider = new CustomUserChecksProvider(); 24 | 25 | private static final Logger LOGGER = Loggers.get(CustomUserChecksRulesDefinition.class); 26 | 27 | public CustomUserChecksRulesDefinition(Settings settings) { 28 | this.settings = settings; 29 | } 30 | 31 | private void defineRulesForLanguage(final Context context) { 32 | 33 | final String[] paths = settings.getStringArray(Constants.PLUGIN_CUSTOM_RULES_PATH); 34 | final String rulesPrefix = settings.getString(Constants.PLUGIN_CUSTOM_RULES_PREFIX); 35 | final Map rules = provider.getRules(null, rulesPrefix, paths); 36 | 37 | for (final String key : rules.keySet()) { 38 | final SqlRules type = rules.get(key); 39 | if (type.isIsAdhoc()) { 40 | continue; 41 | } 42 | final String repositoryKey = type.getRepoKey(); 43 | final String repositoryName = type.getRepoName(); 44 | final NewRepository repository = context.createRepository(repositoryKey, TSQLLanguage.KEY) 45 | .setName(repositoryName); 46 | try (final InputStream rulesXml = new FileInputStream(key)) { 47 | final RulesDefinitionXmlLoader rulesLoader = new RulesDefinitionXmlLoader(); 48 | rulesLoader.load(repository, rulesXml, StandardCharsets.UTF_8.name()); 49 | } catch (FileNotFoundException e) { 50 | LOGGER.info("File was not found: " + key); 51 | } catch (IOException e1) { 52 | LOGGER.info("Error reading file: " + key); 53 | } 54 | 55 | repository.done(); 56 | } 57 | 58 | } 59 | 60 | @Override 61 | public void define(final Context context) { 62 | defineRulesForLanguage(context); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/definitions/MsRulesDefinition.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.definitions; 2 | 3 | import org.sonar.plugins.tsql.Constants; 4 | 5 | public final class MsRulesDefinition extends BaseRulesDefinition { 6 | 7 | public MsRulesDefinition() { 8 | super(Constants.MS_REPO_KEY, Constants.MS_REPO_NAME, Constants.MS_RULES_FILE); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/files/BaseReportsProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.files; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | import org.apache.commons.lang.StringUtils; 9 | 10 | public class BaseReportsProvider implements IReportsProvider { 11 | 12 | private final String searchName; 13 | 14 | public BaseReportsProvider(final String searchName) { 15 | this.searchName = searchName.toLowerCase(); 16 | } 17 | 18 | @Override 19 | public File[] get(final String baseDir) { 20 | if (StringUtils.isEmpty(this.searchName)) { 21 | return new File[0]; 22 | } 23 | 24 | final List res = new ArrayList<>(); 25 | final List files = listf(baseDir); 26 | for (final File f : files) { 27 | if (f.getName().toLowerCase().endsWith(this.searchName)) { 28 | res.add(f); 29 | } 30 | } 31 | return res.toArray(new File[0]); 32 | } 33 | 34 | private static List listf(final String directoryName) { 35 | final File directory = new File(directoryName); 36 | 37 | final List resultList = new ArrayList(); 38 | 39 | if (!directory.exists()) { 40 | return resultList; 41 | } 42 | 43 | final File[] fList = directory.listFiles(); 44 | resultList.addAll(Arrays.asList(fList)); 45 | for (final File file : fList) { 46 | if (file.isDirectory()) { 47 | resultList.addAll(listf(file.getAbsolutePath())); 48 | } 49 | } 50 | return resultList; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/files/FilesProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.files; 2 | 3 | import java.io.File; 4 | import java.util.Arrays; 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | import java.util.stream.Collectors; 8 | 9 | import org.sonar.api.utils.log.Logger; 10 | import org.sonar.api.utils.log.Loggers; 11 | 12 | public class FilesProvider { 13 | private static final Logger LOGGER = Loggers.get(FilesProvider.class); 14 | 15 | public File[] getFiles(String prefix, String actualValue, String baseDir) { 16 | final List foundFiles = new LinkedList<>(); 17 | try { 18 | final File temp = new File(actualValue); 19 | // actual file specified 20 | if (temp.exists() && temp.isFile()) { 21 | foundFiles.add(temp); 22 | } 23 | 24 | // directory specified 25 | 26 | if (temp.exists() && temp.isDirectory()) { 27 | final IReportsProvider reportsProvider = new BaseReportsProvider(prefix); 28 | final File[] files = reportsProvider.get(temp.getAbsolutePath()); 29 | foundFiles.addAll(Arrays.asList(files).stream().filter(File::isFile).collect(Collectors.toList())); 30 | } 31 | 32 | // relative or search path specified 33 | if (!temp.exists()) { 34 | final IReportsProvider reportsProvider = new BaseReportsProvider(actualValue); 35 | final File[] files = reportsProvider.get(baseDir); 36 | foundFiles.addAll(Arrays.asList(files).stream().filter(File::isFile).collect(Collectors.toList())); 37 | } 38 | 39 | } catch (final Throwable e) { 40 | 41 | LOGGER.warn( 42 | "Unexpected error was thrown while searching for files: prefix {} actualValue {} baseDir {}. Exception was: {} ", 43 | prefix, actualValue, baseDir, e); 44 | } 45 | return foundFiles.stream().distinct().collect(Collectors.toList()).toArray(new File[0]); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/files/IReportsProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.files; 2 | 3 | import java.io.File; 4 | 5 | public interface IReportsProvider { 6 | File[] get(String file); 7 | } 8 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/issues/CodeGuardIssuesProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.issues; 2 | 3 | import static java.lang.String.format; 4 | 5 | import java.io.File; 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.List; 9 | 10 | import org.sonar.api.config.Settings; 11 | import org.sonar.api.utils.TempFolder; 12 | import org.sonar.api.utils.log.Logger; 13 | import org.sonar.api.utils.log.Loggers; 14 | import org.sonar.plugins.tsql.rules.files.CodeGuardExecutingReportsProvider; 15 | import org.sonar.plugins.tsql.rules.files.IReportsProvider; 16 | import org.sonar.plugins.tsql.rules.parsers.CodeGuardIssuesParser; 17 | import org.sonar.plugins.tsql.rules.parsers.IIssuesParser; 18 | 19 | public class CodeGuardIssuesProvider implements IIssuesProvider { 20 | 21 | private final IIssuesParser issuesParser = new CodeGuardIssuesParser(); 22 | private final IReportsProvider reportsProvider; 23 | 24 | private static final Logger LOGGER = Loggers.get(CodeGuardIssuesProvider.class); 25 | 26 | public CodeGuardIssuesProvider(final Settings settings, final TempFolder tempFolder) { 27 | this.reportsProvider = new CodeGuardExecutingReportsProvider(settings, tempFolder); 28 | } 29 | 30 | @Override 31 | public TsqlIssue[] getIssues(final String baseDir) { 32 | final List foundIssues = new ArrayList(); 33 | for (final File reportPath : this.reportsProvider.get(baseDir)) { 34 | final TsqlIssue[] errors = this.issuesParser.parse(reportPath); 35 | LOGGER.debug(format("Found total %d issues at %s.", errors.length, reportPath)); 36 | foundIssues.addAll(Arrays.asList(errors)); 37 | } 38 | return foundIssues.toArray(new TsqlIssue[0]); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/issues/DefaultIssuesFiller.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.issues; 2 | 3 | import static java.lang.String.format; 4 | 5 | import org.sonar.api.batch.fs.FileSystem; 6 | import org.sonar.api.batch.fs.InputFile; 7 | import org.sonar.api.batch.rule.Severity; 8 | import org.sonar.api.batch.sensor.SensorContext; 9 | import org.sonar.api.batch.sensor.issue.NewExternalIssue; 10 | import org.sonar.api.batch.sensor.issue.NewIssue; 11 | import org.sonar.api.batch.sensor.issue.NewIssueLocation; 12 | import org.sonar.api.rule.RuleKey; 13 | import org.sonar.api.rules.RuleType; 14 | import org.sonar.api.utils.log.Logger; 15 | import org.sonar.api.utils.log.Loggers; 16 | 17 | public class DefaultIssuesFiller implements IIssuesFiller { 18 | private static final Logger LOGGER = Loggers.get(DefaultIssuesFiller.class); 19 | 20 | @Override 21 | public void fill(final SensorContext context, final InputFile inputFile, final TsqlIssue... issues) { 22 | 23 | for (final TsqlIssue tsqlIssue : issues) { 24 | InputFile file = inputFile; 25 | if (tsqlIssue == null) { 26 | continue; 27 | } 28 | try { 29 | if (tsqlIssue.getLine() < 1) { 30 | LOGGER.warn(format("Can't add issue %s on file %s as line is 0", tsqlIssue.getType(), 31 | tsqlIssue.getFilePath())); 32 | continue; 33 | } 34 | 35 | if (file == null) { 36 | final FileSystem fileSystem = context.fileSystem(); 37 | file = fileSystem.inputFile(fileSystem.predicates().and(tsqlIssue.getPredicate())); 38 | 39 | if (file == null) { 40 | LOGGER.debug(format("Cound not find file %s to add issue %s at line %d.", 41 | tsqlIssue.getFilePath(), tsqlIssue.getType(), tsqlIssue.getLine())); 42 | continue; 43 | } 44 | } 45 | final RuleKey rule = RuleKey.of(tsqlIssue.getRepositoryKey(), tsqlIssue.getType()); 46 | 47 | if (tsqlIssue.isExternal()) { 48 | final NewExternalIssue externalIssue = context.newExternalIssue().engineId(tsqlIssue.getRepositoryKey()) 49 | .ruleId(tsqlIssue.getType()).severity(Severity.INFO).type(RuleType.CODE_SMELL); 50 | final NewIssueLocation loc = externalIssue.newLocation().on(file) 51 | .at(file.selectLine(tsqlIssue.getLine())); 52 | if (tsqlIssue.getDescription() != null) { 53 | loc.message(tsqlIssue.getDescription()); 54 | } 55 | externalIssue.at(loc).save(); 56 | continue; 57 | } 58 | 59 | final NewIssue issue = context.newIssue().forRule(rule); 60 | final NewIssueLocation loc = issue.newLocation().on(file).at(file.selectLine(tsqlIssue.getLine())); 61 | if (tsqlIssue.getDescription() != null) { 62 | loc.message(tsqlIssue.getDescription()); 63 | } 64 | 65 | issue.at(loc).save(); 66 | } catch (final Throwable e) { 67 | LOGGER.warn(format("Can't add issue %s on file %s at line %d.", tsqlIssue.getType(), file, 68 | tsqlIssue.getLine()), e); 69 | } 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/issues/IIssuesFiller.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.issues; 2 | 3 | import org.sonar.api.batch.fs.InputFile; 4 | import org.sonar.api.batch.sensor.SensorContext; 5 | 6 | public interface IIssuesFiller { 7 | void fill(SensorContext context, final InputFile file, TsqlIssue... issues); 8 | } 9 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/issues/IIssuesProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.issues; 2 | 3 | public interface IIssuesProvider { 4 | TsqlIssue[] getIssues(final String baseDir); 5 | } 6 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/issues/MsIssuesProvider.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.issues; 2 | 3 | import static java.lang.String.format; 4 | 5 | import java.io.File; 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.List; 9 | 10 | import org.sonar.api.config.Settings; 11 | import org.sonar.api.utils.log.Logger; 12 | import org.sonar.api.utils.log.Loggers; 13 | import org.sonar.plugins.tsql.Constants; 14 | import org.sonar.plugins.tsql.rules.files.FilesProvider; 15 | import org.sonar.plugins.tsql.rules.parsers.IIssuesParser; 16 | import org.sonar.plugins.tsql.rules.parsers.MsIssuesParser; 17 | 18 | public class MsIssuesProvider implements IIssuesProvider { 19 | 20 | private final IIssuesParser issuesParser = new MsIssuesParser(); 21 | 22 | private static final Logger LOGGER = Loggers.get(MsIssuesProvider.class); 23 | private final FilesProvider filesProvider = new FilesProvider(); 24 | private final Settings settings; 25 | 26 | public MsIssuesProvider(final Settings settings) { 27 | this.settings = settings; 28 | } 29 | 30 | @Override 31 | public TsqlIssue[] getIssues(String baseDir) { 32 | final List foundIssues = new ArrayList(); 33 | File[] files = filesProvider.getFiles(Constants.MS_REPORT_FILE_DEFAULT_VALUE, 34 | settings.getString(Constants.MS_REPORT_FILE), baseDir); 35 | for (final File reportPath : files) { 36 | final TsqlIssue[] errors = this.issuesParser.parse(reportPath); 37 | LOGGER.debug(format("Found total %d issues at %s.", errors.length, reportPath)); 38 | foundIssues.addAll(Arrays.asList(errors)); 39 | } 40 | return foundIssues.toArray(new TsqlIssue[0]); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/issues/TsqlIssue.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.issues; 2 | 3 | import org.sonar.api.batch.fs.FilePredicate; 4 | import org.sonar.plugins.tsql.predicates.AbsolutePathCaseInsensitivePredicate; 5 | 6 | public class TsqlIssue { 7 | 8 | private String type; 9 | 10 | private String description; 11 | private boolean isExternal; 12 | public boolean isExternal() { 13 | return isExternal; 14 | } 15 | 16 | public void setExternal(boolean isExternal) { 17 | this.isExternal = isExternal; 18 | } 19 | 20 | private String filePath; 21 | private int line; 22 | private String repositoryKey; 23 | public String getRepositoryKey() { 24 | return repositoryKey; 25 | } 26 | 27 | public void setRepositoryKey(String repositoryKey) { 28 | this.repositoryKey = repositoryKey; 29 | } 30 | 31 | public String getType() { 32 | return type; 33 | } 34 | 35 | public void setType(final String type) { 36 | this.type = type; 37 | } 38 | 39 | public String getDescription() { 40 | return description; 41 | } 42 | 43 | public void setDescription(final String description) { 44 | this.description = description; 45 | } 46 | 47 | public String getFilePath() { 48 | return filePath; 49 | } 50 | 51 | public void setFilePath(final String filePath) { 52 | this.filePath = filePath; 53 | } 54 | 55 | public int getLine() { 56 | return line; 57 | } 58 | 59 | public void setLine(final int line) { 60 | this.line = line; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return this.getType() + " " + this.getDescription() + " " + this.getFilePath() + " " + this.getLine(); 66 | } 67 | 68 | public FilePredicate getPredicate() { 69 | return new AbsolutePathCaseInsensitivePredicate(this.getFilePath()); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/parsers/CodeGuardIssuesParser.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.parsers; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import javax.xml.bind.JAXBContext; 8 | import javax.xml.bind.Unmarshaller; 9 | 10 | import org.sonar.api.utils.log.Logger; 11 | import org.sonar.api.utils.log.Loggers; 12 | import org.sonar.plugins.tsql.rules.issues.CodeGuardIssues; 13 | import org.sonar.plugins.tsql.rules.issues.CodeGuardIssues.File.Issue; 14 | import org.sonar.plugins.tsql.rules.issues.TsqlIssue; 15 | 16 | public class CodeGuardIssuesParser implements IIssuesParser { 17 | 18 | private static final Logger LOGGER = Loggers.get(CodeGuardIssuesParser.class); 19 | 20 | @Override 21 | public TsqlIssue[] parse(final File file) { 22 | final List list = new ArrayList(); 23 | try { 24 | final JAXBContext jaxbContext = JAXBContext.newInstance(CodeGuardIssues.class); 25 | final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); 26 | final CodeGuardIssues issues = (CodeGuardIssues) jaxbUnmarshaller.unmarshal(file); 27 | for (final org.sonar.plugins.tsql.rules.issues.CodeGuardIssues.File f : issues.getFile()) { 28 | for (final Issue is : f.getIssue()) { 29 | final TsqlIssue issue = new TsqlIssue(); 30 | issue.setDescription(is.getText()); 31 | issue.setFilePath(f.getFullname()); 32 | issue.setLine(is.getLine()); 33 | issue.setType(is.getCode()); 34 | list.add(issue); 35 | } 36 | 37 | } 38 | return list.toArray(new TsqlIssue[0]); 39 | 40 | } catch (final Throwable e) { 41 | LOGGER.warn("Unexpected error occured redading file "+file, e); 42 | } 43 | return new TsqlIssue[0]; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/parsers/IIssuesParser.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.parsers; 2 | 3 | import java.io.File; 4 | 5 | public interface IIssuesParser { 6 | T[] parse(final File file); 7 | } 8 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/rules/parsers/MsIssuesParser.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.parsers; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import javax.xml.bind.JAXBContext; 8 | import javax.xml.bind.Unmarshaller; 9 | 10 | import org.sonar.api.utils.log.Logger; 11 | import org.sonar.api.utils.log.Loggers; 12 | import org.sonar.plugins.tsql.rules.issues.MsIssues; 13 | import org.sonar.plugins.tsql.rules.issues.MsIssues.Problem; 14 | import org.sonar.plugins.tsql.rules.issues.TsqlIssue; 15 | 16 | public class MsIssuesParser implements IIssuesParser { 17 | 18 | private static final Logger LOGGER = Loggers.get(MsIssuesParser.class); 19 | 20 | @Override 21 | public TsqlIssue[] parse(final File file) { 22 | final List list = new ArrayList(); 23 | try { 24 | final JAXBContext jaxbContext = JAXBContext.newInstance(MsIssues.class); 25 | final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); 26 | final MsIssues issues = (MsIssues) jaxbUnmarshaller.unmarshal(file); 27 | for (final Problem p : issues.getProblem()) { 28 | final TsqlIssue issue = new TsqlIssue(); 29 | issue.setDescription(p.getProblemDescription()); 30 | issue.setFilePath(p.getSourceFile()); 31 | issue.setLine(p.getLine()); 32 | issue.setType(p.getRule()); 33 | list.add(issue); 34 | } 35 | return list.toArray(new TsqlIssue[0]); 36 | } catch (final Throwable e) { 37 | LOGGER.warn("Unexpected error occured reading file: " + file, e); 38 | } 39 | return new TsqlIssue[0]; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/sensors/BaseTsqlExternalSensor.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.sensors; 2 | 3 | import static java.lang.String.format; 4 | 5 | import org.sonar.plugins.tsql.rules.issues.DefaultIssuesFiller; 6 | import org.sonar.plugins.tsql.rules.issues.IIssuesFiller; 7 | import org.sonar.plugins.tsql.rules.issues.IIssuesProvider; 8 | import org.sonar.plugins.tsql.rules.issues.TsqlIssue; 9 | 10 | public class BaseTsqlExternalSensor extends BaseTsqlSensor { 11 | 12 | private final IIssuesProvider issuesProvider; 13 | private final String repositoryKey; 14 | private final IIssuesFiller filler = new DefaultIssuesFiller(); 15 | 16 | public BaseTsqlExternalSensor(final IIssuesProvider issuesProvider, final String sensorName, 17 | final String repositoryKey) { 18 | super(sensorName); 19 | this.issuesProvider = issuesProvider; 20 | this.repositoryKey = repositoryKey; 21 | 22 | } 23 | 24 | protected void innerExecute(final org.sonar.api.batch.sensor.SensorContext context) { 25 | 26 | final String baseDir = context.fileSystem().baseDir().getAbsolutePath(); 27 | 28 | final TsqlIssue[] issues = this.issuesProvider.getIssues(baseDir); 29 | 30 | for (final TsqlIssue i : issues) { 31 | i.setRepositoryKey(this.repositoryKey); 32 | } 33 | LOGGER.info(format("Found %d issues", issues.length)); 34 | 35 | filler.fill(context, null, issues); 36 | 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/sensors/BaseTsqlSensor.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.sensors; 2 | 3 | import org.sonar.api.batch.sensor.SensorDescriptor; 4 | import org.sonar.api.config.Settings; 5 | import org.sonar.api.utils.log.Logger; 6 | import org.sonar.api.utils.log.Loggers; 7 | import org.sonar.plugins.tsql.Constants; 8 | import org.sonar.plugins.tsql.languages.TSQLLanguage; 9 | 10 | public abstract class BaseTsqlSensor implements org.sonar.api.batch.sensor.Sensor { 11 | 12 | protected static final Logger LOGGER = Loggers.get(BaseTsqlSensor.class); 13 | private final String sensorName; 14 | 15 | public BaseTsqlSensor(final String sensorName) { 16 | this.sensorName = sensorName; 17 | } 18 | 19 | @Override 20 | public String toString() { 21 | return this.getClass().getSimpleName(); 22 | } 23 | 24 | @Override 25 | public void describe(final SensorDescriptor descriptor) { 26 | descriptor.name(this.getClass().getSimpleName()).onlyOnLanguage(TSQLLanguage.KEY); 27 | } 28 | 29 | @Override 30 | public void execute(final org.sonar.api.batch.sensor.SensorContext context) { 31 | 32 | final Settings settings = context.settings(); 33 | final boolean skipAnalysis = settings.getBoolean(Constants.PLUGIN_SKIP); 34 | 35 | if (skipAnalysis) { 36 | LOGGER.debug(String.format("Skipping plugin as skip flag is set: %s", Constants.PLUGIN_SKIP)); 37 | return; 38 | } 39 | final boolean skipSensor = settings.getBoolean(sensorName); 40 | 41 | if (skipSensor) { 42 | LOGGER.debug(String.format("Skipping sensor as skip flag is set: %s", sensorName)); 43 | return; 44 | } 45 | try { 46 | innerExecute(context); 47 | } catch (Throwable e) { 48 | e.printStackTrace(); 49 | } 50 | } 51 | 52 | protected abstract void innerExecute(final org.sonar.api.batch.sensor.SensorContext context); 53 | } 54 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/sensors/CodeGuardIssuesLoaderSensor.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.sensors; 2 | 3 | import org.sonar.api.config.Settings; 4 | import org.sonar.api.utils.TempFolder; 5 | import org.sonar.plugins.tsql.Constants; 6 | import org.sonar.plugins.tsql.rules.issues.CodeGuardIssuesProvider; 7 | 8 | public class CodeGuardIssuesLoaderSensor extends BaseTsqlExternalSensor { 9 | 10 | public CodeGuardIssuesLoaderSensor(final Settings settings, final TempFolder tempFolder) { 11 | super(new CodeGuardIssuesProvider(settings, tempFolder), Constants.PLUGIN_SKIP_CG, Constants.CG_REPO_KEY); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/java/org/sonar/plugins/tsql/sensors/MsIssuesLoaderSensor.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.sensors; 2 | 3 | import org.sonar.api.config.Settings; 4 | import org.sonar.plugins.tsql.Constants; 5 | import org.sonar.plugins.tsql.rules.issues.MsIssuesProvider; 6 | 7 | public class MsIssuesLoaderSensor extends BaseTsqlExternalSensor { 8 | 9 | public MsIssuesLoaderSensor(final Settings settings) { 10 | super(new MsIssuesProvider(settings), Constants.PLUGIN_SKIP_MS, Constants.MS_REPO_KEY); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/resources/schemas/codeGuard.xsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gretard/sonar-tsql-plugin/aadb5598bbb183c12df997ee9f3e053f962ce0f7/sonar-tsql-plugin/src/main/resources/schemas/codeGuard.xsd -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/resources/schemas/sqlRules.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/resources/schemas/visualStudio.xsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gretard/sonar-tsql-plugin/aadb5598bbb183c12df997ee9f3e053f962ce0f7/sonar-tsql-plugin/src/main/resources/schemas/visualStudio.xsd -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/main/resources/tsql.keywords: -------------------------------------------------------------------------------- 1 | ADD 2 | EXTERNAL 3 | PROCEDURE 4 | ALL 5 | FETCH 6 | PUBLIC 7 | ALTER 8 | FILE 9 | RAISERROR 10 | AND 11 | FILLFACTOR 12 | READ 13 | ANY 14 | FOR 15 | READTEXT 16 | AS 17 | FOREIGN 18 | RECONFIGURE 19 | ASC 20 | FREETEXT 21 | REFERENCES 22 | AUTHORIZATION 23 | FREETEXTTABLE 24 | REPLICATION 25 | BACKUP 26 | FROM 27 | RESTORE 28 | BEGIN 29 | FULL 30 | RESTRICT 31 | BETWEEN 32 | FUNCTION 33 | RETURN 34 | BREAK 35 | GOTO 36 | REVERT 37 | BROWSE 38 | GRANT 39 | REVOKE 40 | BULK 41 | GROUP 42 | RIGHT 43 | BY 44 | HAVING 45 | ROLLBACK 46 | CASCADE 47 | HOLDLOCK 48 | ROWCOUNT 49 | CASE 50 | IDENTITY 51 | ROWGUIDCOL 52 | CHECK 53 | IDENTITY_INSERT 54 | RULE 55 | CHECKPOINT 56 | IDENTITYCOL 57 | SAVE 58 | CLOSE 59 | IF 60 | SCHEMA 61 | CLUSTERED 62 | IN 63 | SECURITYAUDIT 64 | COALESCE 65 | INDEX 66 | SELECT 67 | COLLATE 68 | INNER 69 | SEMANTICKEYPHRASETABLE 70 | COLUMN 71 | INSERT 72 | SEMANTICSIMILARITYDETAILSTABLE 73 | COMMIT 74 | INTERSECT 75 | SEMANTICSIMILARITYTABLE 76 | COMPUTE 77 | INTO 78 | SESSION_USER 79 | CONSTRAINT 80 | IS 81 | SET 82 | CONTAINS 83 | JOIN 84 | SETUSER 85 | CONTAINSTABLE 86 | KEY 87 | SHUTDOWN 88 | CONTINUE 89 | KILL 90 | SOME 91 | CONVERT 92 | LEFT 93 | STATISTICS 94 | CREATE 95 | LIKE 96 | SYSTEM_USER 97 | CROSS 98 | LINENO 99 | TABLE 100 | CURRENT 101 | LOAD 102 | TABLESAMPLE 103 | CURRENT_DATE 104 | MERGE 105 | TEXTSIZE 106 | CURRENT_TIME 107 | NATIONAL 108 | THEN 109 | CURRENT_TIMESTAMP 110 | NOCHECK 111 | TO 112 | CURRENT_USER 113 | NONCLUSTERED 114 | TOP 115 | CURSOR 116 | NOT 117 | TRAN 118 | DATABASE 119 | NULL 120 | TRANSACTION 121 | DBCC 122 | NULLIF 123 | TRIGGER 124 | DEALLOCATE 125 | OF 126 | TRUNCATE 127 | DECLARE 128 | OFF 129 | TRY_CONVERT 130 | DEFAULT 131 | OFFSETS 132 | TSEQUAL 133 | DELETE 134 | ON 135 | UNION 136 | DENY 137 | OPEN 138 | UNIQUE 139 | DESC 140 | OPENDATASOURCE 141 | UNPIVOT 142 | DISK 143 | OPENQUERY 144 | UPDATE 145 | DISTINCT 146 | OPENROWSET 147 | UPDATETEXT 148 | DISTRIBUTED 149 | OPENXML 150 | USE 151 | DOUBLE 152 | OPTION 153 | USER 154 | DROP 155 | OR 156 | VALUES 157 | DUMP 158 | ORDER 159 | VARYING 160 | ELSE 161 | OUTER 162 | VIEW 163 | END 164 | OVER 165 | WAITFOR 166 | ERRLVL 167 | PERCENT 168 | WHEN 169 | ESCAPE 170 | PIVOT 171 | WHERE 172 | EXCEPT 173 | PLAN 174 | WHILE 175 | EXEC 176 | PRECISION 177 | WITH 178 | EXECUTE 179 | PRIMARY 180 | WITHIN GROUP 181 | EXISTS 182 | PRINT 183 | WRITETEXT 184 | EXIT 185 | PROC 186 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/antlr/CustomRulesVerificationTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr; 2 | 3 | import java.util.Collection; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.junit.runners.Parameterized; 11 | import org.junit.runners.Parameterized.Parameters; 12 | import org.sonar.plugins.tsql.checks.CustomPluginChecks; 13 | import org.sonar.plugins.tsql.checks.custom.Rule; 14 | import org.sonar.plugins.tsql.checks.custom.SqlRules; 15 | import org.sonar.plugins.tsql.helpers.AntlrUtils; 16 | import org.sonar.plugins.tsql.rules.issues.TsqlIssue; 17 | 18 | @RunWith(Parameterized.class) 19 | public class CustomRulesVerificationTest { 20 | private Rule rule; 21 | private String text; 22 | private boolean issuesFound; 23 | private String key; 24 | private String ruleName; 25 | 26 | @Parameters(name = "{index}: {1}={2}") 27 | public static Collection data() { 28 | final List objects = new LinkedList<>(); 29 | final CustomPluginChecks provider = new CustomPluginChecks(); 30 | final SqlRules rules = provider.getRules(); 31 | for (Rule r : rules.getRule()) { 32 | 33 | for (String c : r.getRuleImplementation().getCompliantRulesCodeExamples().getRuleCodeExample()) { 34 | objects.add(new Object[] { r, r.getKey(), r.getName(), c, false }); 35 | } 36 | 37 | for (String c : r.getRuleImplementation().getViolatingRulesCodeExamples().getRuleCodeExample()) { 38 | objects.add(new Object[] { r, r.getKey(), r.getName(), c, true }); 39 | } 40 | } 41 | return objects; 42 | } 43 | 44 | public CustomRulesVerificationTest(Rule rule, String key, String ruleName, String text, boolean issuesFound) { 45 | this.rule = rule; 46 | this.key = key; 47 | this.ruleName = ruleName; 48 | this.text = text; 49 | this.issuesFound = issuesFound; 50 | 51 | } 52 | 53 | @Test 54 | public void test() throws Throwable{ 55 | Assert.assertNotNull("Rule's debt remiationfunction not specified", this.rule.getRemediationFunction()); 56 | Assert.assertNotNull("Rule's DebtRemediationFunctionCoefficient not specified", 57 | this.rule.getDebtRemediationFunctionCoefficient()); 58 | Assert.assertEquals(this.rule.getKey(), this.rule.getInternalKey()); 59 | TsqlIssue[] issues = AntlrUtils.verify(this.rule, this.text); 60 | Assert.assertEquals(String.format("Expected rule %s [%s] for text %s to find issues: %s", this.rule.getName(), 61 | this.key, this.text, this.issuesFound), this.issuesFound, issues.length != 0); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/antlr/lines/DefaultLinesProviderTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.lines; 2 | 3 | import org.antlr.tsql.TSqlLexer; 4 | import org.antlr.tsql.TSqlParser; 5 | import org.antlr.v4.runtime.CharStream; 6 | import org.antlr.v4.runtime.CharStreams; 7 | import org.antlr.v4.runtime.CommonTokenStream; 8 | import org.antlr.v4.runtime.tree.ParseTree; 9 | import org.junit.Assert; 10 | import org.junit.Test; 11 | import org.sonar.plugins.tsql.antlr.lines.DefaultLinesProvider; 12 | import org.sonar.plugins.tsql.antlr.nodes.ParsedNode; 13 | 14 | public class DefaultLinesProviderTest { 15 | 16 | @Test 17 | public void test() { 18 | 19 | final CharStream charStream = CharStreams.fromString("\r\nSELECT\r\n 1"); 20 | 21 | final TSqlLexer lexer = new TSqlLexer(charStream); 22 | 23 | final CommonTokenStream stream = new CommonTokenStream(lexer); 24 | 25 | stream.fill(); 26 | TSqlParser parser = new TSqlParser(stream); 27 | ParseTree child = parser.tsql_file().getChild(0); 28 | DefaultLinesProvider lines = new DefaultLinesProvider(stream); 29 | int line = lines.getLine(new ParsedNode(child)); 30 | Assert.assertEquals(2, line); 31 | 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/antlr/nodes/NodeUsesProviderTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes; 2 | 3 | import org.antlr.v4.runtime.tree.ParseTree; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | import org.sonar.plugins.tsql.antlr.IParsedNode; 7 | import org.sonar.plugins.tsql.helpers.AntlrUtils; 8 | import org.sonar.plugins.tsql.helpers.TestNode; 9 | 10 | public class NodeUsesProviderTest { 11 | 12 | @Test 13 | public void testGetUsesNodes() throws Throwable { 14 | String s = "SELECT *,test from dbo.test where name like '%test%' ;"; 15 | ParseTree tree = AntlrUtils.getRequest(s).getRoot(); 16 | NodeUsesProvider provider = new NodeUsesProvider(tree); 17 | IParsedNode[] nodes = provider.getNodes(new TestNode("test", null, 0)); 18 | Assert.assertEquals(28, nodes.length); 19 | } 20 | 21 | @Test 22 | public void testGetUsesNodesNull() throws Throwable { 23 | String s = "SELECT *,test from dbo.test where name like '%test%' ;"; 24 | ParseTree tree = AntlrUtils.getRequest(s).getRoot(); 25 | NodeUsesProvider provider = new NodeUsesProvider(tree); 26 | IParsedNode[] nodes = provider.getNodes(null); 27 | Assert.assertEquals(0, nodes.length); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/antlr/nodes/NodesMatchingRulesProviderTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | import org.junit.Test; 7 | import org.sonar.plugins.tsql.antlr.CandidateNode; 8 | import org.sonar.plugins.tsql.antlr.CandidateRule; 9 | import org.sonar.plugins.tsql.antlr.IParsedNode; 10 | import org.sonar.plugins.tsql.antlr.issues.NodesMatchingRulesProvider; 11 | import org.sonar.plugins.tsql.checks.custom.Rule; 12 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 13 | import org.sonar.plugins.tsql.helpers.TestNode; 14 | 15 | import junit.framework.Assert; 16 | 17 | public class NodesMatchingRulesProviderTest { 18 | NodesMatchingRulesProvider sut = new NodesMatchingRulesProvider(new INodesProvider() { 19 | 20 | @Override 21 | public IParsedNode[] getNodes(IParsedNode node) { 22 | return new IParsedNode[] { new TestNode("test", "test", 2) }; 23 | } 24 | }); 25 | 26 | @Test 27 | public void testCheck() { 28 | Rule rule = new Rule(); 29 | RuleImplementation child = new RuleImplementation(); 30 | RuleImplementation imp = new RuleImplementation(); 31 | imp.getChildrenRules().getRuleImplementation().add(child); 32 | rule.setRuleImplementation(imp); 33 | CandidateRule candidateRule = new CandidateRule("test", rule); 34 | IParsedNode nnode = new TestNode("test", "testClass", 1); 35 | Map> results = sut.check(new CandidateNode(candidateRule, nnode)); 36 | Assert.assertEquals(2, results.size()); 37 | Assert.assertEquals(1, results.get(rule.getRuleImplementation()).size()); 38 | } 39 | 40 | @Test(expected = IllegalArgumentException.class) 41 | public void testCheckNull() { 42 | Map> results = sut.check(null); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/antlr/nodes/ParsedNodeTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes; 2 | 3 | import org.antlr.tsql.TSqlParser.Cfl_statementContext; 4 | import org.antlr.v4.runtime.tree.ParseTree; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.sonar.plugins.tsql.antlr.IParsedNode; 8 | import org.sonar.plugins.tsql.helpers.AntlrUtils; 9 | 10 | public class ParsedNodeTest { 11 | 12 | @Test 13 | public void testGetChildren() throws Throwable { 14 | String s = "SELECT * from dbo.test where name like '%test%' ;"; 15 | ParseTree tree = AntlrUtils.getRequest(s).getRoot(); 16 | ParsedNode node = new ParsedNode(tree); 17 | IParsedNode[] nodes = node.getChildren(); 18 | 19 | Assert.assertEquals(43, nodes.length); 20 | 21 | } 22 | 23 | @Test 24 | public void testControlFlowParent() throws Throwable { 25 | String s = "IF @a > 0 SELECT 1 else SELECT 2;"; 26 | ParseTree tree = AntlrUtils.getRequest(s).getRoot(); 27 | ParsedNode node = new ParsedNode(tree.getChild(0).getChild(0).getChild(0).getChild(0).getChild(0).getChild(0)); 28 | IParsedNode parentNode = node.getControlFlowParent(); 29 | Assert.assertNotNull(parentNode); 30 | Assert.assertEquals(Cfl_statementContext.class.getSimpleName(), parentNode.getClassName()); 31 | } 32 | 33 | @Test 34 | public void testControlFlowParentNotContrl() throws Throwable { 35 | String s = "SELECT 1;"; 36 | ParseTree tree = AntlrUtils.getRequest(s).getRoot(); 37 | ParsedNode node = new ParsedNode(tree.getChild(0).getChild(0)); 38 | IParsedNode parentNode = node.getControlFlowParent(); 39 | Assert.assertNotNull(parentNode); 40 | Assert.assertEquals(null, parentNode.getClassName()); 41 | } 42 | 43 | @Test 44 | public void testGetItemNull() throws Throwable { 45 | ParsedNode node = new ParsedNode(null); 46 | Assert.assertEquals(0, node.getChildren().length); 47 | Assert.assertEquals(0, node.getParents().length); 48 | Assert.assertEquals(0, node.getSiblings().length); 49 | Assert.assertNotNull(node.getControlFlowParent()); 50 | Assert.assertNull(node.getText()); 51 | } 52 | 53 | @Test 54 | public void testSiblings() throws Throwable { 55 | String s = "SELECT * from dbo.test where name like '%test%' ;"; 56 | ParseTree tree = AntlrUtils.getRequest(s).getRoot().getChild(0).getChild(0).getChild(0).getChild(0); 57 | ParsedNode node = new ParsedNode(tree); 58 | IParsedNode[] nodes = node.getSiblings(); 59 | Assert.assertEquals(39, nodes.length); 60 | 61 | } 62 | 63 | @Test 64 | public void testParents() throws Throwable { 65 | String s = "SELECT * from dbo.test where name like '%test%' ;"; 66 | ParseTree tree = AntlrUtils.getRequest(s).getRoot().getChild(0).getChild(0).getChild(0).getChild(0); 67 | ParsedNode node = new ParsedNode(tree); 68 | IParsedNode[] nodes = node.getParents(); 69 | Assert.assertEquals(4, nodes.length); 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/antlr/nodes/matchers/DistanceMatcherTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.antlr.nodes.matchers; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collection; 5 | 6 | import org.junit.Assert; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.junit.runners.Parameterized; 10 | import org.junit.runners.Parameterized.Parameters; 11 | import org.sonar.plugins.tsql.antlr.IParsedNode; 12 | import org.sonar.plugins.tsql.antlr.nodes.matchers.DistanceMatcher; 13 | import org.sonar.plugins.tsql.checks.custom.RuleDistanceIndexMatchType; 14 | import org.sonar.plugins.tsql.checks.custom.RuleImplementation; 15 | import org.sonar.plugins.tsql.helpers.TestNode; 16 | 17 | @RunWith(Parameterized.class) 18 | public class DistanceMatcherTest { 19 | @Parameters 20 | public static Collection data() { 21 | return Arrays.asList( 22 | new Object[][] { { RuleDistanceIndexMatchType.DEFAULT, 0, new TestNode("test", "test", 1, 1, 1), true }, 23 | { RuleDistanceIndexMatchType.MORE, 1, new TestNode("test", "test", 0, 2, 1), false }, 24 | { RuleDistanceIndexMatchType.MORE, 1, new TestNode("test", "test", 1, 0, 1), true }, 25 | { RuleDistanceIndexMatchType.LESS, 1, new TestNode("test", "test", 0, 1, 2), true }, 26 | { RuleDistanceIndexMatchType.LESS, 2, new TestNode("test", "test", 1, 1, 2), true }, 27 | { RuleDistanceIndexMatchType.LESS, 2, new TestNode("test", "test", 10, 5, 2), false }, 28 | { RuleDistanceIndexMatchType.EQUALS, 2, new TestNode("test", "test", 2, 2, 2), true }, 29 | { RuleDistanceIndexMatchType.EQUALS, 2, new TestNode("test", "test", 1, 5, 2), false }, 30 | 31 | }); 32 | } 33 | 34 | private boolean result; 35 | private IParsedNode node; 36 | private int distance; 37 | private RuleDistanceIndexMatchType type; 38 | private final DistanceMatcher matcher = new DistanceMatcher(); 39 | 40 | public DistanceMatcherTest(RuleDistanceIndexMatchType type, int distance, IParsedNode node, boolean result) { 41 | this.type = type; 42 | this.distance = distance; 43 | this.node = node; 44 | this.result = result; 45 | 46 | } 47 | 48 | @Test 49 | public void test() { 50 | RuleImplementation rule = new RuleImplementation(); 51 | rule.setDistance(this.distance); 52 | rule.setDistanceCheckType(this.type); 53 | Assert.assertEquals(String.format("Expected %s, %s with type %s index1: %s index2 %s", result, type, 54 | this.distance, node.getIndex(), node.getIndex2()), 55 | 56 | this.result, matcher.match(rule, this.node)); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/coverage/FileNamesMatcherTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.coverage; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | import com.google.common.collect.ImmutableMap; 7 | 8 | public class FileNamesMatcherTest { 9 | FileNamesMatcher sut = new FileNamesMatcher(); 10 | @Test 11 | public void testMatchWithNoSchema() { 12 | CoveredLinesReport[] lines = sut.match("[tes t].sql","src", 13 | ImmutableMap.of("dbo.test", new CoveredLinesReport("[dbo].[test]"), "other.test", new CoveredLinesReport("[other].[test"))); 14 | Assert.assertEquals(2, lines.length); 15 | } 16 | 17 | @Test 18 | public void testMatchWithNoSchemaAndParent() { 19 | CoveredLinesReport[] lines = sut.match("[tes t].sql","dbo", 20 | ImmutableMap.of("dbo.test", new CoveredLinesReport("[dbo].[test]"), "other.test", new CoveredLinesReport("[other].[test"))); 21 | Assert.assertEquals(1, lines.length); 22 | } 23 | @Test 24 | public void testMatchWithSchemaAndParent() { 25 | CoveredLinesReport[] lines = sut.match("dbo.[tes t].sql","dbo", 26 | ImmutableMap.of("dbo.test", new CoveredLinesReport("[dbo].[test]"), "other.test", new CoveredLinesReport("[other].[test"))); 27 | Assert.assertEquals(1, lines.length); 28 | } 29 | @Test 30 | public void testNoMatch() { 31 | 32 | CoveredLinesReport[] lines = sut.match("[test2].sql", "src", 33 | ImmutableMap.of("dbo.test", new CoveredLinesReport("[dbo].[test]"), "other.test", new CoveredLinesReport("[other].[test"))); 34 | Assert.assertEquals(0, lines.length); 35 | } 36 | 37 | @Test 38 | public void testMatchWithSchema() { 39 | CoveredLinesReport[] lines = sut.match("dbo.t est.sql","src", 40 | ImmutableMap.of("dbo.test", new CoveredLinesReport("[dbo].[test]"), "other.test", new CoveredLinesReport("[other].[test"))); 41 | Assert.assertEquals(1, lines.length); 42 | } 43 | 44 | @Test 45 | public void testMatchWithSchema2() { 46 | CoveredLinesReport[] lines = sut.match("dbo.test.sql", "src",ImmutableMap.of("dbo.test", new CoveredLinesReport("[dbo].[test]"), "other.test", new CoveredLinesReport("[other].[test"))); 47 | Assert.assertEquals(1, lines.length); 48 | } 49 | 50 | @Test 51 | public void testMatchWithSchema3() { 52 | CoveredLinesReport[] lines = sut.match("db.dbo.test.sql", "src",ImmutableMap.of("dbo.test", new CoveredLinesReport("[dbo].[test]"), "other.test", new CoveredLinesReport("[other].[test"))); 53 | Assert.assertEquals(1, lines.length); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/helpers/AntrlResult.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.helpers; 2 | 3 | import org.antlr.tsql.TSqlParser; 4 | import org.antlr.v4.runtime.CommonTokenStream; 5 | import org.antlr.v4.runtime.tree.ParseTree; 6 | 7 | public class AntrlResult { 8 | private ParseTree tree; 9 | private CommonTokenStream stream; 10 | private TSqlParser parser; 11 | public ParseTree getTree() { 12 | return tree; 13 | } 14 | public void setTree(ParseTree tree) { 15 | this.tree = tree; 16 | } 17 | public CommonTokenStream getStream() { 18 | return stream; 19 | } 20 | public void setStream(CommonTokenStream stream) { 21 | this.stream = stream; 22 | } 23 | public void setParser(TSqlParser parser) { 24 | this.parser = parser; 25 | // TODO Auto-generated method stub 26 | 27 | } 28 | public TSqlParser getParser() { 29 | return parser; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/helpers/ClassesLister.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.helpers; 2 | 3 | import java.util.Set; 4 | import java.util.TreeSet; 5 | 6 | import org.antlr.v4.runtime.ParserRuleContext; 7 | import org.antlr.v4.runtime.tree.ParseTree; 8 | import org.reflections.Reflections; 9 | 10 | public class ClassesLister { 11 | 12 | public static void main(String[] args) { 13 | Reflections reflections = new Reflections("org.antlr.tsql"); 14 | Set> subTypes = reflections.getSubTypesOf(ParserRuleContext.class); 15 | TreeSet ordered = new TreeSet<>(); 16 | for (@SuppressWarnings("rawtypes") Class c : subTypes) { 17 | ordered.add(c.getSimpleName()); 18 | } 19 | for (String x : ordered) { 20 | System.out.println("- " + x); 21 | } 22 | System.out.println(ordered.size()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/helpers/CustomRulesPrinter.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.helpers; 2 | 3 | import org.sonar.plugins.tsql.checks.CustomPluginChecks; 4 | import org.sonar.plugins.tsql.checks.custom.Rule; 5 | import org.sonar.plugins.tsql.checks.custom.SqlRules; 6 | 7 | public class CustomRulesPrinter { 8 | 9 | public static void main(String[] args) { 10 | final CustomPluginChecks provider = new CustomPluginChecks(); 11 | final SqlRules rules = provider.getRules(); 12 | 13 | for (Rule r : rules.getRule()) { 14 | for (String c : r.getRuleImplementation().getCompliantRulesCodeExamples().getRuleCodeExample()) { 15 | System.out.println(String.format("-- OK: %s", r.getKey())); 16 | System.out.println(String.format("%s", c)); 17 | } 18 | for (String c : r.getRuleImplementation().getViolatingRulesCodeExamples().getRuleCodeExample()) { 19 | System.out.println(String.format("-- KO: %s", r.getKey())); 20 | System.out.println(String.format("%s", c)); 21 | } 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/helpers/CustomSqlCodePrinter.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.helpers; 2 | 3 | import org.sonar.plugins.tsql.checks.CustomPluginChecks; 4 | import org.sonar.plugins.tsql.checks.custom.Rule; 5 | import org.sonar.plugins.tsql.checks.custom.SqlRules; 6 | 7 | public class CustomSqlCodePrinter { 8 | 9 | public static void main(String[] args) { 10 | final CustomPluginChecks provider = new CustomPluginChecks(); 11 | final SqlRules rules = provider.getRules(); 12 | System.out.println("# Rules #"); 13 | System.out.println(); 14 | System.out.println(String.format("Plugin supports the following %s rules:", rules.getRule().size())); 15 | System.out.println(); 16 | for (Rule r : rules.getRule()) { 17 | System.out.println(String.format("- %s - %s", r.getKey(), r.getName())); 18 | } 19 | System.out.println(); 20 | for (Rule r : rules.getRule()) { 21 | System.out.println(String.format("## %s - %s ##", r.getKey(), r.getName())); 22 | System.out.println(r.getDescription().replace("

Description

", "")); 23 | System.out.println(); 24 | if (!r.getRuleImplementation().getCompliantRulesCodeExamples().getRuleCodeExample().isEmpty()) { 25 | System.out.println("### Compliant examples ###"); 26 | System.out.println(); 27 | for (String c : r.getRuleImplementation().getCompliantRulesCodeExamples().getRuleCodeExample()) { 28 | System.out.println(String.format("`%s`\r\n", c)); 29 | } 30 | } 31 | 32 | if (!r.getRuleImplementation().getViolatingRulesCodeExamples().getRuleCodeExample().isEmpty()) { 33 | System.out.println("### Non-compliant examples ###"); 34 | System.out.println(); 35 | for (String c : r.getRuleImplementation().getViolatingRulesCodeExamples().getRuleCodeExample()) { 36 | System.out.println(String.format("`%s`\r\n", c)); 37 | } 38 | } 39 | } 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/helpers/RulesHelperTool.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.helpers; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | 7 | import org.apache.commons.io.IOUtils; 8 | import org.sonar.plugins.tsql.antlr.AntlrContext; 9 | import org.sonar.plugins.tsql.checks.custom.Rule; 10 | import org.sonar.plugins.tsql.checks.custom.SqlRules; 11 | import org.sonar.plugins.tsql.rules.issues.TsqlIssue; 12 | 13 | public class RulesHelperTool { 14 | 15 | public static void main(String[] args) throws FileNotFoundException, IOException { 16 | if (args.length != 3) { 17 | System.out.println("Please pass the following: "); 18 | System.out.println("\taction (print or verify)"); 19 | System.out.println("\ttype (text or file)"); 20 | System.out.println("\tvalue (sql string or path to folder) "); 21 | System.out.println("Example:\r\nprint text \"SELECT * FROM dbo.test;\""); 22 | System.out.println("Example:\r\nverify file \"c:/tests/customRules.rules;\""); 23 | 24 | return; 25 | } 26 | 27 | String action = args[0]; 28 | String type = args[1]; 29 | String value = args[2]; 30 | String text = value; 31 | if (!"text".equals(type)) { 32 | text = IOUtils.toString(new FileInputStream(value), "UTF-8"); 33 | } 34 | if ("print".equalsIgnoreCase(action)) { 35 | System.out.println("Printing tree:\r\n"); 36 | AntlrContext result = AntlrUtils.getRequest(text); 37 | 38 | AntlrUtils.print(result.getRoot(), 0, result.getStream()); 39 | return; 40 | 41 | } 42 | System.out.println("text"); 43 | SqlRules[] rules = AntlrUtils.read(value); 44 | 45 | for (SqlRules rule : rules) { 46 | System.out.println("Checking repository: " + rule.getRepoName()); 47 | for (Rule r : rule.getRule()) { 48 | System.out.println("Checking rule: " + r.getKey()); 49 | for (String s : r.getRuleImplementation().getCompliantRulesCodeExamples().getRuleCodeExample()) { 50 | boolean res = AntlrUtils.verify(r, s).length == 0; 51 | System.out.println("\tc passed: " + res + " for " + s); 52 | } 53 | for (String s : r.getRuleImplementation().getViolatingRulesCodeExamples().getRuleCodeExample()) { 54 | TsqlIssue[] iss = AntlrUtils.verify(r, s); 55 | boolean res = iss.length > 0; 56 | System.out.println("\tv passed: " + res + " for " + s); 57 | } 58 | 59 | } 60 | } 61 | 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/helpers/TestNode.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.helpers; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.antlr.v4.runtime.tree.ParseTree; 7 | import org.sonar.plugins.tsql.antlr.IParsedNode; 8 | 9 | public class TestNode implements IParsedNode { 10 | 11 | private String text; 12 | private String className; 13 | private int distance; 14 | private TestNode parent; 15 | private int index; 16 | private int index2; 17 | private final List innerParents = new ArrayList<>(); 18 | private final List innerChildren = new ArrayList<>(); 19 | 20 | public List getInnerParents() { 21 | return innerParents; 22 | } 23 | 24 | public List getInnerChildren() { 25 | return innerChildren; 26 | } 27 | 28 | public List getInnerSiblings() { 29 | return innerSiblings; 30 | } 31 | 32 | private final List innerSiblings = new ArrayList<>(); 33 | 34 | public void setParent(TestNode parent) { 35 | this.parent = parent; 36 | } 37 | 38 | public TestNode(String text, String className, int distance) { 39 | this.text = text; 40 | this.className = className; 41 | this.distance = distance; 42 | } 43 | 44 | public TestNode(String text, String className, int distance, int index) { 45 | this.text = text; 46 | this.className = className; 47 | this.distance = distance; 48 | this.index = index; 49 | } 50 | 51 | public TestNode(String text, String className, int distance, int index, int index2) { 52 | this.text = text; 53 | this.className = className; 54 | this.distance = distance; 55 | this.index = index; 56 | this.index2 = index2; 57 | 58 | } 59 | 60 | @Override 61 | public String getText() { 62 | return text; 63 | } 64 | 65 | @Override 66 | public String getClassName() { 67 | return className; 68 | } 69 | 70 | @Override 71 | public int getDistance() { 72 | return distance; 73 | } 74 | 75 | @Override 76 | public ParseTree getItem() { 77 | return null; 78 | } 79 | 80 | @Override 81 | public IParsedNode getControlFlowParent() { 82 | return parent; 83 | } 84 | 85 | @Override 86 | public int getIndex() { 87 | // TODO Auto-generated method stub 88 | return index; 89 | } 90 | 91 | @Override 92 | public int getIndex2() { 93 | // TODO Auto-generated method stub 94 | return this.index2; 95 | } 96 | 97 | @Override 98 | public IParsedNode[] getParents() { 99 | return this.innerParents.toArray(new IParsedNode[0]); 100 | } 101 | 102 | @Override 103 | public IParsedNode[] getChildren() { 104 | return this.innerChildren.toArray(new IParsedNode[0]); 105 | } 106 | 107 | @Override 108 | public IParsedNode[] getSiblings() { 109 | return this.innerSiblings.toArray(new IParsedNode[0]); 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/languages/TSQLLanguageTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.languages; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | import org.sonar.api.config.Settings; 6 | import org.sonar.plugins.tsql.Constants; 7 | 8 | public class TSQLLanguageTest { 9 | 10 | @Test 11 | public void testDefaultSuffixes() { 12 | final Settings settings = new org.sonar.api.config.internal.MapSettings(); 13 | final TSQLLanguage language = new TSQLLanguage(settings); 14 | Assert.assertArrayEquals(new String[] { ".sql" }, language.getFileSuffixes()); 15 | } 16 | 17 | @Test 18 | public void testDefinedSuffixes() { 19 | final Settings settings = new org.sonar.api.config.internal.MapSettings(); 20 | settings.setProperty(Constants.PLUGIN_SUFFIXES, ".sql,.test"); 21 | final TSQLLanguage language = new TSQLLanguage(settings); 22 | Assert.assertArrayEquals(new String[] { ".sql", ".test" }, language.getFileSuffixes()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/languages/keywords/KeywordsProviderTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.languages.keywords; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class KeywordsProviderTest { 7 | 8 | @Test 9 | public void test() { 10 | KeywordsProvider provider = new KeywordsProvider(); 11 | Assert.assertFalse(provider.isKeyword("test")); 12 | } 13 | 14 | @Test 15 | public void testKeyword() { 16 | KeywordsProvider provider = new KeywordsProvider(); 17 | Assert.assertTrue(provider.isKeyword("SELECT")); 18 | } 19 | 20 | @Test 21 | public void testInitializeNonExisting() { 22 | KeywordsProvider provider = new KeywordsProvider("nonExisting"); 23 | Assert.assertFalse(provider.isKeyword("SELECT")); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/lines/SourceLinesProviderTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.lines; 2 | 3 | import java.io.BufferedWriter; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.OutputStreamWriter; 9 | import java.nio.charset.Charset; 10 | import java.nio.charset.StandardCharsets; 11 | 12 | import org.apache.commons.io.FileUtils; 13 | import org.junit.Assert; 14 | import org.junit.Rule; 15 | import org.junit.Test; 16 | import org.junit.rules.TemporaryFolder; 17 | 18 | public class SourceLinesProviderTest { 19 | @Rule 20 | public TemporaryFolder folder = new TemporaryFolder(); 21 | 22 | @Test 23 | public void testGetLines() throws IOException { 24 | folder.create(); 25 | String s = "select * from dbo.test\r\n" + "--test"; 26 | File ff = folder.newFile("test.sql"); 27 | FileUtils.write(ff, s, StandardCharsets.UTF_8); 28 | SourceLinesProvider sut = new SourceLinesProvider(); 29 | SourceLine[] results = sut.getLines(new FileInputStream(ff), Charset.defaultCharset()); 30 | Assert.assertEquals(2, results.length); 31 | Assert.assertEquals(24, results[0].getCount()); 32 | 33 | } 34 | 35 | @Test 36 | public void testGetLines2() throws IOException { 37 | SourceLinesProvider sut = new SourceLinesProvider(); 38 | SourceLine[] results = sut.getLines(null, Charset.defaultCharset()); 39 | Assert.assertEquals(0, results.length); 40 | 41 | } 42 | 43 | @Test 44 | public void testGetLinesBOM() throws IOException { 45 | folder.create(); 46 | File ff = folder.newFile("test.sql"); 47 | BufferedWriter out = new BufferedWriter( 48 | new OutputStreamWriter(new FileOutputStream(ff), StandardCharsets.UTF_8)); 49 | out.write('\ufeff'); 50 | out.write('a'); 51 | out.flush(); 52 | out.close(); 53 | 54 | SourceLinesProvider sut = new SourceLinesProvider(); 55 | SourceLine[] results = sut.getLines(new FileInputStream(ff), StandardCharsets.UTF_8); 56 | Assert.assertEquals(1, results.length); 57 | Assert.assertEquals(1, results[0].getCount()); 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/rules/BaseReportsProviderTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules; 2 | 3 | import java.io.File; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.sonar.plugins.tsql.rules.files.BaseReportsProvider; 8 | 9 | public class BaseReportsProviderTest { 10 | 11 | @Test 12 | public void testGetNonExistingDir() { 13 | BaseReportsProvider cut = new BaseReportsProvider("test.xml"); 14 | File[] files = cut.get("./test"); 15 | Assert.assertEquals(0, files.length); 16 | } 17 | 18 | @Test 19 | public void testGetFilesInExistingDir() { 20 | String file = this.getClass().getClassLoader().getResource(".").getFile(); 21 | 22 | BaseReportsProvider cut = new BaseReportsProvider(".xml"); 23 | File[] files = cut.get(file); 24 | Assert.assertEquals(5, files.length); 25 | } 26 | 27 | @Test 28 | public void testGetSpecificFile() { 29 | String file = this.getClass().getClassLoader().getResource(".").getFile(); 30 | 31 | BaseReportsProvider cut = new BaseReportsProvider("Gsample.xml"); 32 | File[] files = cut.get(file); 33 | Assert.assertEquals(1, files.length); 34 | } 35 | } -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/rules/CgSqlIssuesParserTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules; 2 | 3 | import java.io.File; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.sonar.plugins.tsql.rules.issues.TsqlIssue; 8 | import org.sonar.plugins.tsql.rules.parsers.CodeGuardIssuesParser; 9 | 10 | public class CgSqlIssuesParserTest { 11 | 12 | @Test 13 | public void testParser() { 14 | 15 | String file = this.getClass().getClassLoader().getResource("cgSample.xml").getFile(); 16 | CodeGuardIssuesParser parser = new CodeGuardIssuesParser(); 17 | 18 | TsqlIssue[] issues = parser.parse(new File(file)); 19 | Assert.assertNotNull("Returned issues was null", issues); 20 | Assert.assertEquals("Expected 1 issues", 1, issues.length); 21 | TsqlIssue issue = issues[0]; 22 | Assert.assertEquals("Descpriptions did not match", 23 | "Script should end with GO", 24 | issue.getDescription()); 25 | Assert.assertEquals("File path", "C:\\TestTable.sql", issue.getFilePath()); 26 | Assert.assertEquals("Line did not match", 6, issue.getLine()); 27 | Assert.assertEquals("Descpriptions did not match", "SC001", issue.getType()); 28 | 29 | 30 | } 31 | 32 | @Test 33 | public void testParserNonExising() { 34 | 35 | String file = "test.file"; 36 | CodeGuardIssuesParser parser = new CodeGuardIssuesParser(); 37 | 38 | TsqlIssue[] issues = parser.parse(new File(file)); 39 | Assert.assertNotNull("Returned issues was null", issues); 40 | 41 | 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/rules/VsSqlIssuesParserTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules; 2 | 3 | import java.io.File; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.sonar.plugins.tsql.rules.issues.TsqlIssue; 8 | import org.sonar.plugins.tsql.rules.parsers.MsIssuesParser; 9 | 10 | public class VsSqlIssuesParserTest { 11 | 12 | private final MsIssuesParser parser = new MsIssuesParser(); 13 | 14 | @Test 15 | public void testParser() { 16 | String file = this.getClass().getClassLoader().getResource("vsSample.xml").getFile(); 17 | TsqlIssue[] issues = parser.parse(new File(file)); 18 | Assert.assertNotNull("Returned issues was null", issues); 19 | Assert.assertEquals("Expected a single issue", 1, issues.length); 20 | TsqlIssue issue = issues[0]; 21 | Assert.assertEquals("Descpriptions did not match", 22 | "The shape of the result set produced by a SELECT * statement will change if the underlying table or view structure changes.", 23 | issue.getDescription()); 24 | Assert.assertEquals("File path", "c:\\Database1\\Procedure1.sql", issue.getFilePath()); 25 | Assert.assertEquals("Line did not match", 6, issue.getLine()); 26 | Assert.assertEquals("Descpriptions did not match", "Microsoft.Rules.Data.SR0001", issue.getType()); 27 | 28 | } 29 | 30 | @Test 31 | public void testParserNonExistingFile() { 32 | final String file = "test"; 33 | TsqlIssue[] issues = parser.parse(new File(file)); 34 | Assert.assertNotNull("Returned issues was null", issues); 35 | Assert.assertEquals("Expected a single issue", 0, issues.length); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/rules/definitions/CustomUserChecksProviderTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.definitions; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.Map; 6 | 7 | import org.apache.commons.io.FileUtils; 8 | import org.junit.Assert; 9 | import org.junit.Test; 10 | import org.sonar.api.utils.internal.JUnitTempFolder; 11 | import org.sonar.plugins.tsql.checks.CustomUserChecksProvider; 12 | import org.sonar.plugins.tsql.checks.custom.SqlRules; 13 | 14 | public class CustomUserChecksProviderTest { 15 | @org.junit.Rule 16 | public JUnitTempFolder temp = new JUnitTempFolder(); 17 | 18 | @Test 19 | public void testGetRules() throws IOException { 20 | File baseFile = temp.newFile("rulesTest", "xml"); 21 | FileUtils.copyURLToFile(getClass().getResource("/customrulesSample.xml"), baseFile); 22 | 23 | CustomUserChecksProvider provider = new CustomUserChecksProvider(); 24 | Map rules = provider.getRules(null, "rules", baseFile.getParentFile().getAbsolutePath()); 25 | Assert.assertEquals(1, rules.size()); 26 | Assert.assertEquals(8, rules.values().toArray(new SqlRules[0])[0].getRule().size()); 27 | } 28 | 29 | @Test 30 | public void testNoRules() throws IOException { 31 | 32 | File baseFile = temp.newFile("ruledsTest", "xml"); 33 | FileUtils.copyURLToFile(getClass().getResource("/customrulesSample.xml"), baseFile); 34 | 35 | CustomUserChecksProvider provider = new CustomUserChecksProvider(); 36 | Map rules = provider.getRules(null, "rules", baseFile.getParentFile().getAbsolutePath()); 37 | Assert.assertEquals(0, rules.size()); 38 | } 39 | 40 | @Test 41 | public void testReadFile() throws IOException { 42 | 43 | File baseFile = temp.newFile("rulesTest", "xml"); 44 | FileUtils.copyURLToFile(getClass().getResource("/customrulesSample.xml"), baseFile); 45 | 46 | CustomUserChecksProvider provider = new CustomUserChecksProvider(); 47 | Map rules = provider.getRules(null, "rules", baseFile.getAbsolutePath()); 48 | Assert.assertEquals(1, rules.size()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/rules/files/FilesProviderTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.rules.files; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import org.junit.Assert; 7 | import org.junit.Rule; 8 | import org.junit.Test; 9 | import org.junit.rules.TemporaryFolder; 10 | 11 | public class FilesProviderTest { 12 | 13 | FilesProvider sut = new FilesProvider(); 14 | @Rule 15 | public TemporaryFolder folder = new TemporaryFolder(); 16 | 17 | @Test 18 | public void testNonExisting() { 19 | File[] files = sut.getFiles("test", "test", "."); 20 | Assert.assertEquals(0, files.length); 21 | } 22 | 23 | @Test 24 | public void testDefaultValues() throws IOException { 25 | folder.newFile("aatest.xml"); 26 | File[] files = sut.getFiles("test.xml", "test.xml", folder.getRoot().getAbsolutePath()); 27 | Assert.assertEquals(1, files.length); 28 | 29 | } 30 | 31 | @Test 32 | public void testFolderSpecified() throws IOException { 33 | folder.newFile("aatest.xml"); 34 | File fsFolder = folder.newFolder("sample"); 35 | File[] files = sut.getFiles("test.xml", folder.getRoot().getAbsolutePath(), fsFolder.getAbsolutePath()); 36 | Assert.assertEquals(1, files.length); 37 | } 38 | 39 | @Test 40 | public void testSearchPathSpecified() throws IOException { 41 | folder.newFile("aatest.xml"); 42 | File[] files = sut.getFiles("samplePrefix.xml", "test.xml", folder.getRoot().getAbsolutePath()); 43 | Assert.assertEquals(1, files.length); 44 | } 45 | 46 | @Test 47 | public void testNonExistingSearchPathSpecified() throws IOException { 48 | folder.newFile("aatest.xml"); 49 | File[] files = sut.getFiles("samplePrefix.xml", "a.xml", folder.getRoot().getAbsolutePath()); 50 | Assert.assertEquals(0, files.length); 51 | } 52 | 53 | @Test 54 | public void testFindMultiple() throws IOException { 55 | folder.newFile("aatest.xml"); 56 | folder.newFile("aaBsssjtest.xml"); 57 | 58 | File testFolder = folder.newFolder("test"); 59 | new File(testFolder, "0test.xml").createNewFile(); 60 | new File(testFolder, "0tes.xml").createNewFile(); 61 | File[] files = sut.getFiles("test.xml", "test.xml", folder.getRoot().getAbsolutePath()); 62 | Assert.assertEquals(3, files.length); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/sensors/CoverageSensorTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.sensors; 2 | 3 | import java.io.File; 4 | import java.nio.file.Files; 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | import org.apache.commons.io.FileUtils; 9 | import org.junit.Assert; 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.plugins.tsql.Constants; 16 | import org.sonar.plugins.tsql.coverage.SqlCoverCoverageProvider; 17 | import org.sonar.plugins.tsql.languages.TSQLLanguage; 18 | 19 | public class CoverageSensorTest { 20 | 21 | @Test 22 | public void test() throws Throwable { 23 | TemporaryFolder folder = new TemporaryFolder(); 24 | folder.create(); 25 | 26 | SensorContextTester ctxTester = SensorContextTester.create(folder.getRoot()); 27 | String tempName = "GetStatusMessage.sql"; 28 | String covReport = "test.xml"; 29 | File f = folder.newFile(tempName); 30 | File coverage = folder.newFile(covReport); 31 | 32 | FileUtils.copyInputStreamToFile(this.getClass().getResourceAsStream("/coverage/Coverage.opencoverxml"), 33 | coverage); 34 | 35 | FileUtils.copyInputStreamToFile(this.getClass().getResourceAsStream("/coverage/TestCode.sql"), f); 36 | DefaultInputFile file1 = new TestInputFileBuilder(folder.getRoot().getAbsolutePath(), tempName) 37 | .initMetadata(new String(Files.readAllBytes(f.toPath()))).setLanguage(TSQLLanguage.KEY).build(); 38 | ctxTester.fileSystem().add(file1); 39 | ctxTester.settings().setProperty(Constants.COVERAGE_FILE, coverage.getAbsolutePath()); 40 | ctxTester.settings().setProperty(Constants.PLUGIN_SKIP_COVERAGE, false); 41 | CoverageSensor sut = new CoverageSensor(new SqlCoverCoverageProvider(ctxTester.settings(), ctxTester.fileSystem())); 42 | sut.execute(ctxTester); 43 | Assert.assertEquals((int) 2, (int) ctxTester.lineHits(file1.key(), 7)); 44 | 45 | } 46 | @Test 47 | public void test2() throws Throwable { 48 | List names = Arrays.asList("dbo.test", "test", "other.test"); 49 | 50 | String name = "test"; 51 | 52 | if (names.contains(name)) { 53 | 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/sensors/antlr4/CComplexityVisitorTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.sensors.antlr4; 2 | 3 | import java.io.IOException; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.sonar.plugins.tsql.antlr.AntlrContext; 8 | import org.sonar.plugins.tsql.antlr.visitors.CComplexityVisitor; 9 | import org.sonar.plugins.tsql.antlr.visitors.CustomTreeVisitor; 10 | import org.sonar.plugins.tsql.helpers.AntlrUtils; 11 | 12 | public class CComplexityVisitorTest { 13 | 14 | @Test 15 | public void testIf() throws Throwable { 16 | String s = "IF DATENAME(weekday, GETDATE()) IN (N'Saturday', N'Sunday') SELECT 'Weekend'; ELSE " 17 | + " SELECT 'Weekday';"; 18 | int result = calculate(s); 19 | Assert.assertEquals(2, result); 20 | } 21 | 22 | @Test 23 | public void testCase() throws Throwable { 24 | String s = "SELECT CASE WHEN MIN(value) <= 0 THEN 0 WHEN MAX(1/value) >= 100 THEN 1 ELSE 4 END " 25 | + "FROM testTable ; "; 26 | int result = calculate(s); 27 | Assert.assertEquals(3, result); 28 | } 29 | 30 | @Test 31 | public void testSelectWithWhere() throws Throwable { 32 | String s = "SELECT * from [dbo].[test] where a > 0 or b < 0 and x > 5;"; 33 | 34 | int result = calculate(s); 35 | Assert.assertEquals(4, result); 36 | } 37 | 38 | @Test 39 | public void testReturn() throws Throwable { 40 | String s = "CREATE PROCEDURE checkstate @param varchar(11) AS IF (SELECT StateProvince FROM Person.vAdditionalContactInfo WHERE ContactID = @param) = 'WA' RETURN 1 ELSE RETURN 2; GO "; 41 | int result = calculate(s); 42 | Assert.assertEquals(3, result); 43 | } 44 | 45 | @Test 46 | public void testTryCatch() throws Throwable { 47 | String s = "BEGIN TRY SELECT 1/0; END TRY BEGIN CATCH END CATCH; "; 48 | int result = calculate(s); 49 | Assert.assertEquals(2, result); 50 | } 51 | 52 | @Test 53 | public void testWhile() throws Throwable { 54 | String s = "WHILE @@FETCH_STATUS = 0 BEGIN FETCH NEXT FROM Employee_Cursor; END; "; 55 | int result = calculate(s); 56 | Assert.assertEquals(2, result); 57 | } 58 | 59 | @Test 60 | public void testCase2() throws IOException { 61 | String s = "SELECT case when a > 0 then 'more' when a <0 then 'less' else '0' end from dbo.test"; 62 | int result = calculate(s); 63 | Assert.assertEquals(3, result); 64 | } 65 | 66 | private int calculate(String s) throws IOException { 67 | AntlrContext result = AntlrUtils.getRequest(s); 68 | CComplexityVisitor vv = new CComplexityVisitor(); 69 | CustomTreeVisitor visitor = new CustomTreeVisitor(vv); 70 | visitor.apply(result.getRoot()); 71 | return vv.getMeasure(); 72 | 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/java/org/sonar/plugins/tsql/sensors/antlr4/ComplexityVisitorTest.java: -------------------------------------------------------------------------------- 1 | package org.sonar.plugins.tsql.sensors.antlr4; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | import org.sonar.plugins.tsql.antlr.AntlrContext; 6 | import org.sonar.plugins.tsql.antlr.visitors.ComplexityVisitor; 7 | import org.sonar.plugins.tsql.antlr.visitors.CustomTreeVisitor; 8 | import org.sonar.plugins.tsql.helpers.AntlrUtils; 9 | 10 | public class ComplexityVisitorTest { 11 | 12 | @Test 13 | public void testComplex() throws Throwable { 14 | String s = "SELECT SalesOrderID, SUM(LineTotal) AS SubTotal " 15 | + "FROM Sales.SalesOrderDetail left join dbo.x on t1.id = t2.id where a > 5" 16 | + "GROUP BY SalesOrderID " + "HAVING SUM(LineTotal) > 100000.00 " + "ORDER BY SalesOrderID, test "; 17 | int result = calculate(s); 18 | Assert.assertEquals(11, result); 19 | } 20 | 21 | @Test 22 | public void testSelect() throws Throwable { 23 | String s = "SELECT SalesOrderID, test, * from dbo.test"; 24 | int result = calculate(s); 25 | Assert.assertEquals(4, result); 26 | } 27 | 28 | @Test 29 | public void testWhere() throws Throwable { 30 | String s = "SELECT SalesOrderID, test, * from dbo.test where id > 1 and id2 < 9"; 31 | int result = calculate(s); 32 | Assert.assertEquals(6, result); 33 | } 34 | 35 | @Test 36 | public void testUnion() throws Throwable { 37 | String s = "SELECT a, b from dbo.test union select c,d from dbo.test2"; 38 | int result = calculate(s); 39 | Assert.assertEquals(6, result); 40 | } 41 | 42 | @Test 43 | public void testFunction() throws Throwable { 44 | String s = "SELECT count(a) from dbo.test"; 45 | int result = calculate(s); 46 | Assert.assertEquals(3, result); 47 | } 48 | 49 | @Test 50 | public void testCase() throws Throwable { 51 | String s = "SELECT case when a > 0 then 'more' when a <0 then 'less' else '0' end from dbo.test"; 52 | int result = calculate(s); 53 | Assert.assertEquals(4, result); 54 | } 55 | 56 | private int calculate(String s) throws Throwable { 57 | 58 | AntlrContext result = AntlrUtils.getRequest(s); 59 | ComplexityVisitor vv = new ComplexityVisitor(); 60 | CustomTreeVisitor visitor = new CustomTreeVisitor(vv); 61 | visitor.visit(result.getRoot()); 62 | return vv.getMeasure(); 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/cgSample.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/coverage/Coverage.opencoverxml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gretard/sonar-tsql-plugin/aadb5598bbb183c12df997ee9f3e053f962ce0f7/sonar-tsql-plugin/src/test/resources/coverage/Coverage.opencoverxml -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/coverage/TestCode.sql: -------------------------------------------------------------------------------- 1 | 2 | CREATE FUNCTION Accelerator.GetStatusMessage() 3 | RETURNS NVARCHAR(MAX) 4 | AS 5 | BEGIN 6 | DECLARE @NumParticles INT; 7 | SELECT @NumParticles = COUNT(1) FROM Accelerator.Particle; 8 | RETURN 'The Accelerator is prepared with ' + CAST(@NumParticles AS NVARCHAR(MAX)) + ' particles.'; 9 | END; 10 | 11 | 12 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/coverage/[Accelerator].[AlertParticleDiscovered]: -------------------------------------------------------------------------------- 1 | 2 | CREATE PROCEDURE Accelerator.AlertParticleDiscovered 3 | @ParticleDiscovered NVARCHAR(MAX) 4 | AS 5 | BEGIN 6 | IF @ParticleDiscovered = 'Higgs Boson' 7 | BEGIN 8 | EXEC Accelerator.SendHiggsBosonDiscoveryEmail 'particle-discovery@new-era-particles.tsqlt.org'; 9 | END; 10 | END; 11 | 12 | 13 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/coverage/[Accelerator].[GetStatusMessage]: -------------------------------------------------------------------------------- 1 | 2 | CREATE FUNCTION Accelerator.GetStatusMessage() 3 | RETURNS NVARCHAR(MAX) 4 | AS 5 | BEGIN 6 | DECLARE @NumParticles INT; 7 | SELECT @NumParticles = COUNT(1) FROM Accelerator.Particle; 8 | RETURN 'The Accelerator is prepared with ' + CAST(@NumParticles AS NVARCHAR(MAX)) + ' particles.'; 9 | END; 10 | 11 | 12 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/coverage/[Accelerator].[IsExperimentReady]: -------------------------------------------------------------------------------- 1 | 2 | CREATE FUNCTION Accelerator.IsExperimentReady() 3 | RETURNS BIT 4 | AS 5 | BEGIN 6 | DECLARE @NumParticles INT; 7 | 8 | SELECT @NumParticles = COUNT(1) FROM Accelerator.Particle; 9 | 10 | IF @NumParticles > 2 11 | RETURN 1; 12 | 13 | RETURN 0; 14 | END; 15 | 16 | 17 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/coverage/[Accelerator].[SendHiggsBosonDiscoveryEmail]: -------------------------------------------------------------------------------- 1 | 2 | CREATE PROCEDURE Accelerator.SendHiggsBosonDiscoveryEmail 3 | @EmailAddress NVARCHAR(MAX) 4 | AS 5 | BEGIN 6 | RAISERROR('Not Implemented - yet',16,10); 7 | END; 8 | 9 | 10 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/testFiles/TestTable.sql: -------------------------------------------------------------------------------- 1 | GO 2 | --test 3 | SELECT FirstName, MiddleName 4 | FROM Person.Person WHERE LastName = 5 | 'Adams'; 6 | BEGIN TRANSACTION; 7 | 8 | GO 9 | 10 | IF @@TRANCOUNT = 0 11 | 12 | BEGIN 13 | 14 | SELECT FirstName, MiddleName 15 | 16 | FROM Person.Person WHERE LastName = 'Adams'; 17 | 18 | ROLLBACK TRANSACTION; 19 | 20 | PRINT N'Rolling back the transaction two times would cause an error.'; 21 | 22 | END; 23 | 24 | ROLLBACK TRANSACTION; 25 | 26 | PRINT N'Rolled back the transaction.'; 27 | 28 | GO 29 | 30 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/testFiles/cursorFlow.sql: -------------------------------------------------------------------------------- 1 | SET NOCOUNT ON; 2 | 3 | DECLARE @vendor_id int, @vendor_name nvarchar(50), 4 | @message varchar(80), @product nvarchar(50); 5 | 6 | PRINT '-------- Vendor Products Report --------'; 7 | 8 | DECLARE vendor_cursor CURSOR FOR 9 | SELECT VendorID, Name 10 | FROM Purchasing.Vendor 11 | WHERE PreferredVendorStatus = 1 12 | ORDER BY VendorID; 13 | 14 | OPEN vendor_cursor 15 | 16 | FETCH NEXT FROM vendor_cursor 17 | INTO @vendor_id, @vendor_name 18 | 19 | WHILE @@FETCH_STATUS = 0 20 | BEGIN 21 | PRINT ' ' 22 | SELECT @message = '----- Products From Vendor: ' + 23 | @vendor_name 24 | 25 | PRINT @message 26 | 27 | -- Declare an inner cursor based 28 | -- on vendor_id from the outer cursor. 29 | 30 | DECLARE product_cursor CURSOR FOR 31 | SELECT v.Name 32 | FROM Purchasing.ProductVendor pv, Production.Product v 33 | WHERE pv.ProductID = v.ProductID AND 34 | pv.VendorID = @vendor_id -- Variable value from the outer cursor 35 | 36 | OPEN product_cursor 37 | FETCH NEXT FROM product_cursor INTO @product 38 | 39 | IF @@FETCH_STATUS <> 0 40 | PRINT ' <>' 41 | 42 | WHILE @@FETCH_STATUS = 0 43 | BEGIN 44 | 45 | SELECT @message = ' ' + @product 46 | PRINT @message 47 | FETCH NEXT FROM product_cursor INTO @product 48 | END 49 | CLOSE vendor_cursor; 50 | DEALLOCATE vendor_cursor; 51 | CLOSE product_cursor 52 | DEALLOCATE product_cursor 53 | -- Get the next vendor. 54 | FETCH NEXT FROM vendor_cursor 55 | INTO @vendor_id, @vendor_name 56 | END 57 | 58 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/testFiles/cursorFlow2.sql: -------------------------------------------------------------------------------- 1 | SET NOCOUNT ON; 2 | 3 | DECLARE @vendor_id int, @vendor_name nvarchar(50), 4 | @message varchar(80), @product nvarchar(50); 5 | 6 | PRINT '-------- Vendor Products Report --------'; 7 | 8 | DECLARE vendor_cursor CURSOR FOR 9 | SELECT VendorID, Name 10 | FROM Purchasing.Vendor 11 | WHERE PreferredVendorStatus = 1 12 | ORDER BY VendorID; 13 | 14 | OPEN vendor_cursor 15 | 16 | FETCH NEXT FROM vendor_cursor 17 | INTO @vendor_id, @vendor_name 18 | 19 | WHILE @@FETCH_STATUS = 0 20 | BEGIN 21 | PRINT ' ' 22 | SELECT @message = '----- Products From Vendor: ' + 23 | @vendor_name 24 | 25 | PRINT @message 26 | 27 | -- Declare an inner cursor based 28 | -- on vendor_id from the outer cursor. 29 | 30 | DECLARE product_cursor CURSOR FOR 31 | SELECT v.Name 32 | FROM Purchasing.ProductVendor pv, Production.Product v 33 | WHERE pv.ProductID = v.ProductID AND 34 | pv.VendorID = @vendor_id -- Variable value from the outer cursor 35 | 36 | OPEN product_cursor 37 | FETCH NEXT FROM product_cursor INTO @product 38 | 39 | IF @@FETCH_STATUS <> 0 40 | PRINT ' <>' 41 | 42 | WHILE @@FETCH_STATUS = 0 43 | BEGIN 44 | 45 | SELECT @message = ' ' + @product 46 | PRINT @message 47 | FETCH NEXT FROM product_cursor INTO @product 48 | END 49 | 50 | CLOSE product_cursor 51 | DEALLOCATE product_cursor 52 | -- Get the next vendor. 53 | FETCH NEXT FROM vendor_cursor 54 | INTO @vendor_id, @vendor_name 55 | END 56 | CLOSE vendor_cursor; 57 | DEALLOCATE vendor_cursor; -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/testFiles/scriptExample.sql: -------------------------------------------------------------------------------- 1 | SET NOCOUNT ON; 2 | 3 | DECLARE @vendor_id int, @vendor_name nvarchar(50), 4 | @message varchar(80), @product nvarchar(50); 5 | 6 | PRINT '-------- Vendor Products Report --------'; 7 | 8 | DECLARE vendor_cursor CURSOR FOR 9 | SELECT VendorID, Name 10 | FROM Purchasing.Vendor 11 | WHERE PreferredVendorStatus = 1 12 | ORDER BY VendorID; 13 | 14 | OPEN vendor_cursor 15 | 16 | FETCH NEXT FROM vendor_cursor 17 | INTO @vendor_id, @vendor_name 18 | 19 | /*WHILE @@FETCH_STATUS = 0 20 | BEGIN 21 | PRINT ' ' 22 | SELECT @message = '----- Products From Vendor: ' + 23 | @vendor_name 24 | 25 | PRINT @message 26 | 27 | -- Declare an inner cursor based 28 | -- on vendor_id from the outer cursor. 29 | 30 | DECLARE product_cursor CURSOR FOR 31 | SELECT v.Name 32 | FROM Purchasing.ProductVendor pv, Production.Product v 33 | WHERE pv.ProductID = v.ProductID AND 34 | pv.VendorID = @vendor_id -- Variable value from the outer cursor 35 | 36 | OPEN product_cursor 37 | FETCH NEXT FROM product_cursor INTO @product 38 | 39 | IF @@FETCH_STATUS <> 0 40 | PRINT ' <>' 41 | 42 | WHILE @@FETCH_STATUS = 0 43 | BEGIN 44 | 45 | SELECT @message = ' ' + @product 46 | PRINT @message 47 | FETCH NEXT FROM product_cursor INTO @product 48 | END 49 | 50 | CLOSE product_cursor 51 | DEALLOCATE product_cursor 52 | -- Get the next vendor. 53 | FETCH NEXT FROM vendor_cursor 54 | INTO @vendor_id, @vendor_name 55 | END */ 56 | --CLOSE vendor_cursor; 57 | DEALLOCATE vendor_cursor; 58 | 59 | WAITFOR TIME '22:20'; -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/testFiles/scriptExample2.sql: -------------------------------------------------------------------------------- 1 | SET NOCOUNT ON; 2 | 3 | DECLARE @vendor_id int, @vendor_name nvarchar(50), 4 | @message varchar(80), @product nvarchar(50); 5 | 6 | PRINT '-------- Vendor Products Report --------'; 7 | 8 | DECLARE vendor_cursor CURSOR FOR 9 | SELECT VendorID, Name 10 | FROM Purchasing.Vendor 11 | WHERE PreferredVendorStatus = 1 12 | ORDER BY VendorID; 13 | 14 | OPEN vendor_cursor 15 | 16 | FETCH NEXT FROM vendor_cursor 17 | INTO @vendor_id, @vendor_name 18 | 19 | WHILE @@FETCH_STATUS = 0 20 | BEGIN 21 | PRINT ' ' 22 | 23 | DECLARE product_cursor CURSOR FOR 24 | SELECT v.Name 25 | FROM Purchasing.ProductVendor pv, Production.Product v 26 | WHERE pv.ProductID = v.ProductID AND 27 | pv.VendorID = @vendor_id -- Variable value from the outer cursor 28 | 29 | 30 | OPEN product_cursor 31 | FETCH NEXT FROM product_cursor INTO @product 32 | 33 | IF @@FETCH_STATUS <> 0 34 | PRINT ' <>' 35 | 36 | WHILE @@FETCH_STATUS = 0 37 | BEGIN 38 | 39 | SELECT @message = ' ' + @product 40 | PRINT @message 41 | FETCH NEXT FROM product_cursor INTO @product 42 | END 43 | 44 | CLOSE product_cursor 45 | DEALLOCATE product_cursor 46 | 47 | 48 | END 49 | 50 | select * from test 51 | CLOSE vendor_cursor; 52 | 53 | DEALLOCATE vendor_cursor; 54 | 55 | WAITFOR '10:00:00' 56 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/testFiles/scriptExample3.sql: -------------------------------------------------------------------------------- 1 | SELECT * from test -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/testFiles/sp_Get.sql: -------------------------------------------------------------------------------- 1 | create TABLE [dbo].[TestTable] 2 | ( 3 | [Id] INT NOT NULL PRIMARY KEY, 4 | [Name] NVARCHAR(MAX) NULL 5 | ) 6 | --lkasjdkljasd 7 | // askjdhjksad 8 | -------------------------------------------------------------------------------- /sonar-tsql-plugin/src/test/resources/vsSample.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Microsoft.Rules.Data.SR0001 5 | The shape of the result set produced by a SELECT * statement will change if the underlying table or view structure changes. 6 | c:\Database1\Procedure1.sql 7 | 6 8 | 9 9 | Warning 10 | 11 | --------------------------------------------------------------------------------