├── .codeclimate.yml
├── .editorconfig
├── .github
└── workflows
│ └── checkstyle-linux.yml
├── .gitignore
├── .haxerc
├── CHANGELOG.md
├── Checkstyle.hxproj
├── LICENSE.md
├── LIMITATIONS.md
├── README.md
├── build.hxml
├── build
├── Build.hx
├── common.hxml
├── commonCoverage.hxml
└── commonTest.hxml
├── buildAll.hxml
├── buildCpp.hxml
├── buildDebug.hxml
├── buildJS.hxml
├── buildSchema.hxml
├── buildTelemetry.hxml
├── checkstyle.json
├── haxe_libraries
├── compiletime.hxml
├── haxeparser.hxml
├── hxargs.hxml
├── hxcpp.hxml
├── hxjava.hxml
├── hxjsonast.hxml
├── hxnodejs.hxml
├── hxparse.hxml
├── instrument.hxml
├── json2object.hxml
├── mconsole.hxml
├── mcover.hxml
├── mlib.hxml
├── munit.hxml
├── safety.hxml
├── test-adapter.hxml
├── tokentree.hxml
└── utest.hxml
├── haxelib.json
├── hxformat.json
├── makeReleaseZip.sh
├── package-lock.json
├── package.json
├── resources
├── checkstyle-excludes-schema.json
├── checkstyle-schema.json
├── codeclimate_pr.png
├── default-config.json
├── icon.png
├── logo.png
├── logo
│ ├── haxe-checkstyle.png
│ ├── haxe-checkstyle.xcf
│ └── haxe-mono.svg
└── static-analysis.txt
├── schema
├── CheckstyleSchemaGenerator.hx
├── DollarName.hx
├── JsonSchemaGenerator.hx
├── ObjectDeclField.hx
├── SchemaGenerator.hx
├── SchemaUtils.hx
└── StructInfo.hx
├── src
├── CheckstyleVersion.hx
└── checkstyle
│ ├── CheckFile.hx
│ ├── Checker.hx
│ ├── CheckerPool.hx
│ ├── CheckerThread.hx
│ ├── ChecksInfo.hx
│ ├── Main.hx
│ ├── Message.hx
│ ├── ParserQueue.hx
│ ├── SeverityLevel.hx
│ ├── checks
│ ├── Category.hx
│ ├── Check.hx
│ ├── block
│ │ ├── BlockBreakingConditionalCheck.hx
│ │ ├── ConditionalCompilationCheck.hx
│ │ ├── EmptyBlockCheck.hx
│ │ ├── LeftCurlyCheck.hx
│ │ ├── NeedBracesCheck.hx
│ │ └── RightCurlyCheck.hx
│ ├── coding
│ │ ├── ArrowFunctionCheck.hx
│ │ ├── AvoidTernaryOperatorCheck.hx
│ │ ├── CodeSimilarityCheck.hx
│ │ ├── DefaultComesLastCheck.hx
│ │ ├── HiddenFieldCheck.hx
│ │ ├── InnerAssignmentCheck.hx
│ │ ├── MagicNumberCheck.hx
│ │ ├── MultipleVariableDeclarationsCheck.hx
│ │ ├── NestedControlFlowCheck.hx
│ │ ├── NestedForDepthCheck.hx
│ │ ├── NestedIfDepthCheck.hx
│ │ ├── NestedTryDepthCheck.hx
│ │ ├── NullableParameterCheck.hx
│ │ ├── ReturnCountCheck.hx
│ │ ├── SimplifyBooleanExpressionCheck.hx
│ │ ├── SimplifyBooleanReturnCheck.hx
│ │ ├── TraceCheck.hx
│ │ ├── UnusedLocalVarCheck.hx
│ │ └── VariableInitialisationCheck.hx
│ ├── comments
│ │ ├── CommentedOutCodeCheck.hx
│ │ ├── DocCommentStyleCheck.hx
│ │ ├── FieldDocCommentCheck.hx
│ │ ├── TODOCommentCheck.hx
│ │ └── TypeDocCommentCheck.hx
│ ├── design
│ │ ├── EmptyPackageCheck.hx
│ │ ├── InterfaceCheck.hx
│ │ └── UnnecessaryConstructorCheck.hx
│ ├── import.hx
│ ├── imports
│ │ ├── AvoidStarImportCheck.hx
│ │ └── UnusedImportCheck.hx
│ ├── literal
│ │ ├── ArrayLiteralCheck.hx
│ │ ├── ERegLiteralCheck.hx
│ │ ├── HexadecimalLiteralCheck.hx
│ │ ├── MultipleStringLiteralsCheck.hx
│ │ └── StringLiteralCheck.hx
│ ├── meta
│ │ ├── RedundantAccessMetaBase.hx
│ │ ├── RedundantAccessMetaCheck.hx
│ │ ├── RedundantAccessMetaInfo.hx
│ │ └── RedundantAllowMetaCheck.hx
│ ├── metrics
│ │ └── CyclomaticComplexityCheck.hx
│ ├── modifier
│ │ ├── FinalCheck.hx
│ │ ├── ModifierOrderCheck.hx
│ │ ├── PublicAccessorCheck.hx
│ │ └── RedundantModifierCheck.hx
│ ├── naming
│ │ ├── CatchParameterNameCheck.hx
│ │ ├── ConstantNameCheck.hx
│ │ ├── FileNameCaseCheck.hx
│ │ ├── ListenerNameCheck.hx
│ │ ├── LocalVariableNameCheck.hx
│ │ ├── MemberNameCheck.hx
│ │ ├── MethodNameCheck.hx
│ │ ├── NameCheckBase.hx
│ │ ├── ParameterNameCheck.hx
│ │ └── TypeNameCheck.hx
│ ├── size
│ │ ├── FileLengthCheck.hx
│ │ ├── LineLengthCheck.hx
│ │ ├── MethodCountCheck.hx
│ │ ├── MethodLengthCheck.hx
│ │ └── ParameterNumberCheck.hx
│ ├── type
│ │ ├── AnonymousCheck.hx
│ │ ├── AvoidIdentifierCheck.hx
│ │ ├── DynamicCheck.hx
│ │ ├── ReturnCheck.hx
│ │ ├── TypeCheck.hx
│ │ └── VarTypeHintCheck.hx
│ └── whitespace
│ │ ├── ArrayAccessCheck.hx
│ │ ├── EmptyLinesCheck.hx
│ │ ├── ExtendedEmptyLinesCheck.hx
│ │ ├── IndentationCharacterCheck.hx
│ │ ├── IndentationCheck.hx
│ │ ├── LineCheckBase.hx
│ │ ├── ListOfEmptyLines.hx
│ │ ├── OperatorWhitespaceCheck.hx
│ │ ├── OperatorWrapCheck.hx
│ │ ├── SeparatorWhitespaceCheck.hx
│ │ ├── SeparatorWrapCheck.hx
│ │ ├── SpacingCheck.hx
│ │ ├── TabForAligningCheck.hx
│ │ ├── TrailingWhitespaceCheck.hx
│ │ ├── WhitespaceAfterCheck.hx
│ │ ├── WhitespaceAroundCheck.hx
│ │ ├── WhitespaceCheckBase.hx
│ │ └── WrapCheckBase.hx
│ ├── config
│ ├── CheckConfig.hx
│ ├── Config.hx
│ ├── ConfigParser.hx
│ ├── ExcludeConfig.hx
│ ├── ExcludeDefinition.hx
│ ├── ExcludeManager.hx
│ ├── ExcludePath.hx
│ └── ExcludeRange.hx
│ ├── detect
│ ├── DetectCodingStyle.hx
│ ├── DetectableInstance.hx
│ ├── DetectableInstanceProperty.hx
│ ├── DetectableInstances.hx
│ ├── DetectableProperties.hx
│ ├── DetectableProperty.hx
│ ├── DetectablePropertyList.hx
│ ├── DetectionReporter.hx
│ └── DetectionResult.hx
│ ├── errors
│ ├── Error.hx
│ └── InvalidDirectiveError.hx
│ ├── import.hx
│ ├── reporter
│ ├── BaseReporter.hx
│ ├── CodeClimateReporter.hx
│ ├── ExitCodeReporter.hx
│ ├── IReporter.hx
│ ├── JSONReporter.hx
│ ├── ProgressReporter.hx
│ ├── ReporterManager.hx
│ ├── TextReporter.hx
│ └── XMLReporter.hx
│ └── utils
│ ├── ArrayUtils.hx
│ ├── ComplexTypeUtils.hx
│ ├── ConfigUtils.hx
│ ├── DummyMutex.hx
│ ├── DummyThread.hx
│ ├── ErrorUtils.hx
│ ├── ExprUtils.hx
│ ├── FieldUtils.hx
│ ├── Mutex.hx
│ ├── PosHelper.hx
│ ├── StringUtils.hx
│ └── Thread.hx
├── test.hxml
├── test
├── TestMain.hx
├── checkstyle
│ ├── checks
│ │ ├── CheckTestCase.hx
│ │ ├── block
│ │ │ ├── BlockBreakingConditionalCheckTest.hx
│ │ │ ├── BlockTest.hx
│ │ │ ├── ConditionalCompilationCheckTest.hx
│ │ │ ├── EmptyBlockCheckTest.hx
│ │ │ ├── LeftCurlyCheckTest.hx
│ │ │ ├── NeedBracesCheckTest.hx
│ │ │ └── RightCurlyCheckTest.hx
│ │ ├── coding
│ │ │ ├── ArrowFunctionCheckTest.hx
│ │ │ ├── AvoidTernaryOperatorCheckTest.hx
│ │ │ ├── CodeSimilarityCheckTest.hx
│ │ │ ├── DefaultComesLastCheckTest.hx
│ │ │ ├── HiddenFieldCheckTest.hx
│ │ │ ├── InnerAssignmentCheckTest.hx
│ │ │ ├── MagicNumberCheckTest.hx
│ │ │ ├── MultipleVariableDeclarationsCheckTest.hx
│ │ │ ├── NestedControlFlowCheckTest.hx
│ │ │ ├── NestedForDepthCheckTest.hx
│ │ │ ├── NestedIfDepthCheckTest.hx
│ │ │ ├── NestedTryDepthCheckTest.hx
│ │ │ ├── NullableParameterCheckTest.hx
│ │ │ ├── ReturnCountCheckTest.hx
│ │ │ ├── SimplifyBooleanExpressionCheckTest.hx
│ │ │ ├── SimplifyBooleanReturnCheckTest.hx
│ │ │ ├── TraceCheckTest.hx
│ │ │ ├── UnusedLocalVarCheckTest.hx
│ │ │ └── VariableInitialisationCheckTest.hx
│ │ ├── comments
│ │ │ ├── CommentedOutCodeCheckTest.hx
│ │ │ ├── DocCommentStyleCheckTest.hx
│ │ │ ├── FieldDocCommentCheckTest.hx
│ │ │ ├── TODOCommentCheckTest.hx
│ │ │ └── TypeDocCommentCheckTest.hx
│ │ ├── design
│ │ │ ├── EmptyPackageCheckTest.hx
│ │ │ ├── InterfaceCheckTest.hx
│ │ │ └── UnnecessaryConstructorCheckTest.hx
│ │ ├── imports
│ │ │ ├── AvoidStarImportCheckTest.hx
│ │ │ └── UnusedImportCheckTest.hx
│ │ ├── literal
│ │ │ ├── ArrayLiteralCheckTest.hx
│ │ │ ├── ERegLiteralCheckTest.hx
│ │ │ ├── HexadecimalLiteralCheckTest.hx
│ │ │ ├── MultipleStringLiteralsCheckTest.hx
│ │ │ └── StringLiteralCheckTest.hx
│ │ ├── meta
│ │ │ ├── RedundantAccessMetaCheckTest.hx
│ │ │ └── RedundantAllowMetaCheckTest.hx
│ │ ├── metrics
│ │ │ └── CyclomaticComplexityCheckTest.hx
│ │ ├── modifier
│ │ │ ├── FinalCheckTest.hx
│ │ │ ├── ModifierOrderCheckTest.hx
│ │ │ ├── PublicAccessorCheckTest.hx
│ │ │ └── RedundantModifierCheckTest.hx
│ │ ├── naming
│ │ │ ├── CatchParameterNameCheckTest.hx
│ │ │ ├── ConstantNameCheckTest.hx
│ │ │ ├── FileNameCaseCheckTest.hx
│ │ │ ├── ListenerNameCheckTest.hx
│ │ │ ├── LocalVariableNameCheckTest.hx
│ │ │ ├── MemberNameCheckTest.hx
│ │ │ ├── MethodNameCheckTest.hx
│ │ │ ├── ParameterNameCheckTest.hx
│ │ │ └── TypeNameCheckTest.hx
│ │ ├── size
│ │ │ ├── FileLengthCheckTest.hx
│ │ │ ├── LineLengthCheckTest.hx
│ │ │ ├── MethodCountCheckTest.hx
│ │ │ ├── MethodLengthCheckTest.hx
│ │ │ └── ParameterNumberCheckTest.hx
│ │ ├── type
│ │ │ ├── AnonymousCheckTest.hx
│ │ │ ├── AvoidIdentifierCheckTest.hx
│ │ │ ├── DynamicCheckTest.hx
│ │ │ ├── ReturnCheckTest.hx
│ │ │ ├── TypeCheckTest.hx
│ │ │ └── VarTypeHintCheckTest.hx
│ │ └── whitespace
│ │ │ ├── ArrayAccessCheckTest.hx
│ │ │ ├── EmptyLinesCheckTest.hx
│ │ │ ├── ExtendedEmptyLinesCheckTest.hx
│ │ │ ├── IndentationCharacterCheckTest.hx
│ │ │ ├── IndentationCheckTest.hx
│ │ │ ├── OperatorWhitespaceCheckTest.hx
│ │ │ ├── OperatorWrapCheckTest.hx
│ │ │ ├── SeparatorWhitespaceCheckTest.hx
│ │ │ ├── SeparatorWrapCheckTest.hx
│ │ │ ├── SpacingCheckTest.hx
│ │ │ ├── TabForAligningCheckTest.hx
│ │ │ ├── TrailingWhitespaceCheckTest.hx
│ │ │ ├── WhitespaceAfterCheckTest.hx
│ │ │ └── WhitespaceAroundCheckTest.hx
│ ├── config
│ │ ├── ConfigParserTest.hx
│ │ └── ExcludeManagerTest.hx
│ └── detect
│ │ └── DetectCodingStyleTest.hx
├── import.hx
└── misc
│ ├── CheckerTest.hx
│ ├── ExtensionsTest.hx
│ └── ThreadTest.hx
├── testAndResources.hxml
├── testCoverage.hxml
├── testJava.hxml
└── uglifyCheckstyle.sh
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | version: "2"
2 | plugins:
3 | haxe-checkstyle:
4 | enabled: true
5 | markdownlint:
6 | enabled: true
7 | checks:
8 | MD002:
9 | enabled: false
10 | MD013:
11 | enabled: false
12 | MD033:
13 | enabled: false
14 |
15 | exclude_patterns:
16 | - "resources/"
17 | - "node_modules/"
18 | - "haxe_libraries/"
19 | - "haxe3_libraries/"
20 | - "haxe4_libraries/"
21 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # This file is for unifying the coding style for different editors and IDEs.
2 | # More information at http://EditorConfig.org
3 | root = true
4 |
5 | [*]
6 | indent_style = tab
7 | indent_size = 4
8 | insert_final_newline = false
9 | trim_trailing_whitespace = true
10 |
11 | [*.hx]
12 | end_of_line = lf
13 | charset = utf-8
14 |
15 | [*.md]
16 | indent_style = space
17 | indent_size = 2
18 |
19 | [*.yml]
20 | indent_style = space
21 | indent_size = 2
--------------------------------------------------------------------------------
/.github/workflows/checkstyle-linux.yml:
--------------------------------------------------------------------------------
1 | name: Haxe-Checkstyle Linux
2 |
3 | on:
4 | push:
5 | branches:
6 | - dev
7 | pull_request:
8 | branches:
9 | - dev
10 | schedule:
11 | - cron: '15 23 * * *'
12 |
13 | jobs:
14 | build:
15 | runs-on: ubuntu-latest
16 | strategy:
17 | matrix:
18 | haxe-version: ['4.3.6', 'nightly']
19 | env:
20 | CC_TEST_REPORTER_ID: c4eda639526d39fbcab7ab9fc68c4046d4e597df56dbcb552b42d27b3580b758
21 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
22 | steps:
23 | - uses: actions/checkout@v4
24 | - name: Use Node.js 18
25 | uses: actions/setup-node@v4
26 | with:
27 | node-version: 18
28 | - name: Installing codeclimate client
29 | if: matrix.haxe-version == 'nightly'
30 | run: |
31 | curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
32 | chmod +x ./cc-test-reporter
33 | ./cc-test-reporter before-build
34 | - name: Run npm install
35 | run: |
36 | npm ci
37 | npm i -g lix
38 | - name: Install Haxe version ${{ matrix.haxe-version }}
39 | run: |
40 | npx lix download haxe ${{ matrix.haxe-version }}
41 | npx lix use haxe ${{ matrix.haxe-version }}
42 | - name: Run lix download
43 | run: npx lix download
44 | - name: Print versions
45 | run: |
46 | npx haxe -version
47 | npx neko -version
48 | npx haxelib list
49 | - name: Build hxcpp binary
50 | run: |
51 | cd ~/haxe/haxe_libraries/hxcpp/4.2.0/github/96f5f9a69744e5fd07717e5af9d5b45bd3a8890a/
52 | npx haxelib dev hxcpp .
53 | cd tools/hxcpp
54 | npx haxe compile.hxml
55 | - name: Build neko versions
56 | run: |
57 | npx haxe build.hxml
58 | npx haxe buildDebug.hxml
59 | - name: Build NodeJs version
60 | run: |
61 | npx haxe buildJS.hxml
62 | bash uglifyCheckstyle.sh
63 | - name: Build C++ version
64 | run: echo "y" | npx haxe buildCpp.hxml
65 | - name: Build JSON schema
66 | run: npx haxe buildSchema.hxml
67 | - name: Run eval tests
68 | run: npx haxe testAndResources.hxml
69 | - name: Run JVM tests
70 | run: npx haxe testJava.hxml
71 | - name: Upload results to codecov
72 | if: success() && (matrix.haxe-version == 'nightly')
73 | run: bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports"
74 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .idea
3 | .vscode
4 | .temp
5 | *.iws
6 | *.log
7 | *.cache
8 | .DS_Store
9 | *.n
10 | *.zip
11 | out/
12 | node_modules
13 | .DS_Store
14 | log/
15 | target/
16 | callgrind.*
17 | debug/
18 |
19 | check-style-report.json
20 | check-style-report.xml
21 | coverage.json
22 | haxecheckstyle.js
23 |
24 | display.hxml
25 | core
26 | .unittest
27 | lcov.info
28 |
--------------------------------------------------------------------------------
/.haxerc:
--------------------------------------------------------------------------------
1 | {
2 | "version": "4.3.6",
3 | "resolveLibs": "scoped"
4 | }
--------------------------------------------------------------------------------
/Checkstyle.hxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | cmd /c haxe $(OutputFile)
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Adi Reddy Mora
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LIMITATIONS.md:
--------------------------------------------------------------------------------
1 | ## Limitations of checkstyle checks
2 |
3 | checkstyle has three types of checks:
4 |
5 | - Line based
6 | - Token based
7 | - AST based
8 |
9 | Which check uses what type is not instantly clear to the user.
10 |
11 | ### Line based checks
12 |
13 | - scan files line by line
14 | - usually applies a regex to each line
15 | - tries to detect line separator by finding first occurrence of \r, \n or \r\n
16 | - supports all features of Haxe
17 | - can work with files that won't compile
18 |
19 | ### Token based checks
20 |
21 | - relies on HaxeLexer from haxeparser library
22 | - uses work in progress version of token tree builder
23 | - might build incomplete / incorrect tree structure resulting in false positives / negatives
24 | - might result in endless loops or stacktraces
25 | - can be turned off, by not using token tree based checks (excluding them via config.json)
26 | - has position information for all nodes
27 | - access to parent and child nodes
28 | - should support all features of Haxe
29 | - easy search and filter for specific node types
30 | - can work with files that won't compile (limited)
31 |
32 | ### AST based checks
33 |
34 | - relies on HaxeParser from haxeparser library
35 | - partial support for #if, #else, #elseif (only active conditionals)
36 | - macro support unclear (needs to be confirmed / checked)
37 | - no parent info for a given Expr or ComplexType
38 | - position info available only for a subset of all AST nodes
39 | - files must compile
--------------------------------------------------------------------------------
/build.hxml:
--------------------------------------------------------------------------------
1 | build/common.hxml
2 | -main checkstyle.Main
3 | -neko run.n
--------------------------------------------------------------------------------
/build/Build.hx:
--------------------------------------------------------------------------------
1 | import haxe.Timer;
2 |
3 | /**
4 | helper class to build everything, avoids `--next`
5 | **/
6 | class Build {
7 | static var exitCode:Int = 0;
8 |
9 | /**
10 | run all build files
11 | **/
12 | public static function main() {
13 | callLix("build.hxml", "run.n");
14 | callLix("buildDebug.hxml", "runD.n");
15 | callLix("buildJS.hxml", "run.js");
16 | callLix("buildSchema.hxml", "Json schema");
17 | callLix("testAndResources.hxml", "Unittests neko / eval + generate resoucres");
18 | callLix("testJava.hxml", "Unittests Java");
19 | Sys.exit(exitCode);
20 | }
21 |
22 | /**
23 | perform lix call and take build times
24 |
25 | @param buildFile HXML build file
26 | @param title description to use when printing build time
27 | **/
28 | public static function callLix(buildFile:String, title:String) {
29 | var startTime = Timer.stamp();
30 | var result:Int = Sys.command("npx", ["haxe", buildFile]);
31 | Sys.println('building $title (took ${Timer.stamp() - startTime})');
32 | if (result != 0) {
33 | exitCode = result;
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/build/common.hxml:
--------------------------------------------------------------------------------
1 | -cp src
2 | -lib haxeparser
3 | -lib compiletime
4 | -lib hxargs
5 | -lib tokentree
6 | --macro CompileTime.importPackage("checkstyle.checks")
7 |
--------------------------------------------------------------------------------
/build/commonCoverage.hxml:
--------------------------------------------------------------------------------
1 | -lib instrument
2 |
3 | -D coverage-console-summary-reporter
4 | -D coverage-console-file-summary-reporter
5 | -D coverage-console-package-summary-reporter
6 | -D coverage-lcov-reporter
7 | -D coverage-codecov-reporter
8 |
9 | -lib instrument
10 | --macro instrument.Instrumentation.coverage(['checkstyle'], ['src'], [])
11 | # --macro instrument.Instrumentation.coverage(['checkstyle'], ['src'], ['checkstyle.reporter', 'checkstyle.Main'])
12 |
13 | #--macro mcover.MCover.coverage(['checkstyle'], ['src'], ['checkstyle.reporter', 'checkstyle.Main'])
14 |
--------------------------------------------------------------------------------
/build/commonTest.hxml:
--------------------------------------------------------------------------------
1 | build/common.hxml
2 | -cp test
3 | -lib utest
4 | -lib test-adapter
5 | -D unittest
6 | -D UTEST_PRINT_TESTS
7 | # -D UTEST_FAILURE_THROW
8 |
9 | # -debug
10 |
11 | --macro CompileTime.importPackage("checkstyle.checks")
12 | --macro CompileTime.importPackage("misc")
13 |
--------------------------------------------------------------------------------
/buildAll.hxml:
--------------------------------------------------------------------------------
1 | -cp build
2 | --run Build
--------------------------------------------------------------------------------
/buildCpp.hxml:
--------------------------------------------------------------------------------
1 | build/common.hxml
2 | # -lib hxcpp-debugger
3 | # -D HXCPP_DEBUGGER
4 |
5 | # -D HXCPP_STACK_TRACE
6 | # -D HXCPP_STACK_LINE
7 |
8 | # -debug
9 | -main checkstyle.Main
10 | -cpp out
--------------------------------------------------------------------------------
/buildDebug.hxml:
--------------------------------------------------------------------------------
1 | build/common.hxml
2 | -main checkstyle.Main
3 | -debug
4 | -neko runD.n
--------------------------------------------------------------------------------
/buildJS.hxml:
--------------------------------------------------------------------------------
1 | build/common.hxml
2 | -lib hxnodejs
3 | -main checkstyle.Main
4 | -js haxecheckstyle.js
5 |
--------------------------------------------------------------------------------
/buildSchema.hxml:
--------------------------------------------------------------------------------
1 | build/common.hxml
2 | -cp schema
3 | -x SchemaGenerator
4 |
--------------------------------------------------------------------------------
/buildTelemetry.hxml:
--------------------------------------------------------------------------------
1 | build/common.hxml
2 | -lib hxtelemetry
3 |
4 | -D HXCPP_STACK_TRACE
5 | -D HXCPP_TELEMETRY
6 |
7 | -main checkstyle.Main
8 | -cpp out
--------------------------------------------------------------------------------
/haxe_libraries/compiletime.hxml:
--------------------------------------------------------------------------------
1 | -D compiletime=2.8.0
2 | # @install: lix --silent download "haxelib:/compiletime#2.8.0" into compiletime/2.8.0/haxelib
3 | -cp ${HAXE_LIBCACHE}/compiletime/2.8.0/haxelib/src/
4 |
--------------------------------------------------------------------------------
/haxe_libraries/haxeparser.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "gh://github.com/HaxeCheckstyle/haxeparser#49db59c303242c7e6ef1293e35ac5983f31f654d" into haxeparser/4.3.0-rc.1/github/49db59c303242c7e6ef1293e35ac5983f31f654d
2 | -lib hxparse
3 | -cp ${HAXE_LIBCACHE}/haxeparser/4.3.0-rc.1/github/49db59c303242c7e6ef1293e35ac5983f31f654d/src
4 | -D haxeparser=4.3.0-rc.1
--------------------------------------------------------------------------------
/haxe_libraries/hxargs.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "gh://github.com/simn/hxargs#1d8ec84f641833edd6f0cb2e4290b7524fd27219" into hxargs/3.0.2/github/1d8ec84f641833edd6f0cb2e4290b7524fd27219
2 | -cp ${HAXE_LIBCACHE}/hxargs/3.0.2/github/1d8ec84f641833edd6f0cb2e4290b7524fd27219/
3 | -D hxargs=3.0.2
--------------------------------------------------------------------------------
/haxe_libraries/hxcpp.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "gh://github.com/HaxeFoundation/hxcpp#9d9b920a42ecd073a5efaea8c7ad184acec6f479" into hxcpp/4.3.0/github/9d9b920a42ecd073a5efaea8c7ad184acec6f479
2 | # @run: haxelib run-dir hxcpp "${HAXE_LIBCACHE}/hxcpp/4.3.0/github/9d9b920a42ecd073a5efaea8c7ad184acec6f479"
3 | -cp ${HAXE_LIBCACHE}/hxcpp/4.3.0/github/9d9b920a42ecd073a5efaea8c7ad184acec6f479/
4 | -D hxcpp=4.3.0
--------------------------------------------------------------------------------
/haxe_libraries/hxjava.hxml:
--------------------------------------------------------------------------------
1 | -D hxjava=4.0.0-alpha
2 | # @install: lix --silent download "haxelib:/hxjava#4.0.0-alpha" into hxjava/4.0.0-alpha/haxelib
3 | # @run: haxelib run-dir hxjava ${HAXE_LIBCACHE}/hxjava/4.0.0-alpha/haxelib
4 | -cp ${HAXE_LIBCACHE}/hxjava/4.0.0-alpha/haxelib/
5 | -java-lib lib/hxjava-std.jar
6 |
--------------------------------------------------------------------------------
/haxe_libraries/hxjsonast.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "haxelib:/hxjsonast#1.1.0" into hxjsonast/1.1.0/haxelib
2 | -cp ${HAXE_LIBCACHE}/hxjsonast/1.1.0/haxelib/src
3 | -D hxjsonast=1.1.0
--------------------------------------------------------------------------------
/haxe_libraries/hxnodejs.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "haxelib:/hxnodejs#12.2.0" into hxnodejs/12.2.0/haxelib
2 | -cp ${HAXE_LIBCACHE}/hxnodejs/12.2.0/haxelib/src
3 | -D hxnodejs=12.1.0
4 | --macro allowPackage('sys')
5 | # should behave like other target defines and not be defined in macro context
6 | --macro define('nodejs')
7 | --macro _internal.SuppressDeprecated.run()
8 |
--------------------------------------------------------------------------------
/haxe_libraries/hxparse.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "gh://github.com/simn/hxparse#876070ec62a4869de60081f87763e23457a3bda8" into hxparse/4.3.0/github/876070ec62a4869de60081f87763e23457a3bda8
2 | -cp ${HAXE_LIBCACHE}/hxparse/4.3.0/github/876070ec62a4869de60081f87763e23457a3bda8/src
3 | -D hxparse=4.3.0
--------------------------------------------------------------------------------
/haxe_libraries/instrument.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "haxelib:/instrument#1.2.0" into instrument/1.2.0/haxelib
2 | -lib safety
3 | -cp ${HAXE_LIBCACHE}/instrument/1.2.0/haxelib/src
4 | -D instrument=1.2.0
--------------------------------------------------------------------------------
/haxe_libraries/json2object.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "gh://github.com/elnabo/json2object#a75859de1e966c09e73591b6c9186086c143fe60" into json2object/3.11.0/github/a75859de1e966c09e73591b6c9186086c143fe60
2 | -lib hxjsonast
3 | -cp ${HAXE_LIBCACHE}/json2object/3.11.0/github/a75859de1e966c09e73591b6c9186086c143fe60/src
4 | -D json2object=3.11.0
--------------------------------------------------------------------------------
/haxe_libraries/mconsole.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "haxelib:/mconsole#1.6.0" into mconsole/1.6.0/haxelib
2 | -cp ${HAXE_LIBCACHE}/mconsole/1.6.0/haxelib/
3 | -D mconsole=1.6.0
--------------------------------------------------------------------------------
/haxe_libraries/mcover.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "gh://github.com/massive-oss/mcover#c3c47cd682b0b202a41caee95321989391b617ef" into mcover/0.0.0/github/c3c47cd682b0b202a41caee95321989391b617ef
2 | -cp ${HAXE_LIBCACHE}/mcover/0.0.0/github/c3c47cd682b0b202a41caee95321989391b617ef/src
3 | -D mcover=0.0.0
--------------------------------------------------------------------------------
/haxe_libraries/mlib.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "haxelib:/mlib#2.0.3" into mlib/2.0.3/haxelib
2 | # @run: haxelib run-dir mlib ${HAXE_LIBCACHE}/mlib/2.0.3/haxelib
3 | -cp ${HAXE_LIBCACHE}/mlib/2.0.3/haxelib/
4 | -D mlib=2.0.3
--------------------------------------------------------------------------------
/haxe_libraries/munit.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "gh://github.com/AlexHaxe/MassiveUnit#645952947a10d27f2460321eb9c6c9e2a93b997d" into MassiveUnit/0.0.0/github/645952947a10d27f2460321eb9c6c9e2a93b997d
2 | -lib mlib
3 | -cp ${HAXE_LIBCACHE}/MassiveUnit/0.0.0/github/645952947a10d27f2460321eb9c6c9e2a93b997d/src
4 | -D munit=2.3.5
--------------------------------------------------------------------------------
/haxe_libraries/safety.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "haxelib:/safety#1.1.2" into safety/1.1.2/haxelib
2 | -cp ${HAXE_LIBCACHE}/safety/1.1.2/haxelib/src
3 | -D safety=1.1.2
--------------------------------------------------------------------------------
/haxe_libraries/test-adapter.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "haxelib:/test-adapter#2.0.7" into test-adapter/2.0.7/haxelib
2 | -lib json2object
3 | -cp ${HAXE_LIBCACHE}/test-adapter/2.0.7/haxelib/
4 | -D test-adapter=2.0.7
5 | --macro _testadapter.Macro.init()
--------------------------------------------------------------------------------
/haxe_libraries/tokentree.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "haxelib:/tokentree#1.2.17" into tokentree/1.2.17/haxelib
2 | -cp ${HAXE_LIBCACHE}/tokentree/1.2.17/haxelib/src
3 | -D tokentree=1.2.17
--------------------------------------------------------------------------------
/haxe_libraries/utest.hxml:
--------------------------------------------------------------------------------
1 | # @install: lix --silent download "gh://github.com/haxe-utest/utest#f759c0aa257aa723b3dd607cf7cb53d16194d13f" into utest/2.0.0-alpha/github/f759c0aa257aa723b3dd607cf7cb53d16194d13f
2 | -cp ${HAXE_LIBCACHE}/utest/2.0.0-alpha/github/f759c0aa257aa723b3dd607cf7cb53d16194d13f/src
3 | -D utest=2.0.0-alpha
4 | --macro utest.utils.Macro.importEnvSettings()
5 |
--------------------------------------------------------------------------------
/haxelib.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "checkstyle",
3 | "classPath": "src",
4 | "license": "MIT",
5 | "tags": [
6 | "checkstyle",
7 | "haxe",
8 | "standards",
9 | "static",
10 | "analysis",
11 | "coding",
12 | "style",
13 | "cross"
14 | ],
15 | "description": "Automated code analysis ideal for projects that want to enforce a coding standard.",
16 | "contributors": [
17 | "AlexHaxe",
18 | "adireddy",
19 | "Gama11"
20 | ],
21 | "releasenote": "added FileNameCase check - see CHANGELOG",
22 | "version": "2.9.0",
23 | "url": "https://github.com/HaxeCheckstyle/haxe-checkstyle",
24 | "dependencies": {}
25 | }
--------------------------------------------------------------------------------
/hxformat.json:
--------------------------------------------------------------------------------
1 | {
2 | "sameLine": {
3 | "caseBody": "next",
4 | "tryCatch": "next",
5 | "ifBody": "same",
6 | "ifElse": "next",
7 | "elseBody": "same",
8 | "forBody": "same",
9 | "whileBody": "same",
10 | "comprehensionFor": "same"
11 | },
12 | "emptyLines": {
13 | "finalNewline": false,
14 | "lineCommentsBetweenFunctions":"none",
15 | "interfaceEmptyLines": {
16 | "beginType": 1
17 | }
18 | },
19 | "wrapping": {
20 | "arrayWrap": {
21 | "rules": [
22 | {
23 | "conditions": [{"cond": "totalItemLength <= n", "value": 80}],
24 | "type": "noWrap"
25 | },
26 | {
27 | "conditions": [{"cond": "itemCount >= n", "value": 10}],
28 | "type": "onePerLine"
29 | },
30 | {
31 | "conditions": [{"cond": "anyItemLength >= n", "value": 30}],
32 | "type": "onePerLine"
33 | },
34 | {
35 | "conditions": [{"cond": "itemCount >= n", "value": 4}],
36 | "type": "onePerLine"
37 | }
38 | ]
39 | },
40 | "callParameter": {
41 | "defaultWrap": "noWrap",
42 | "rules": [
43 | {
44 | "conditions": [{"cond": "itemCount <= n", "value": 7}],
45 | "type": "fillLine"
46 | },
47 | {
48 | "conditions": [{"cond": "totalItemLength >= n", "value": 140}],
49 | "type": "onePerLineAfterFirst"
50 | },
51 | {
52 | "conditions": [{"cond": "anyItemLength >= n", "value": 120}],
53 | "type": "onePerLineAfterFirst"
54 | },
55 | {
56 | "conditions": [{"cond": "lineLength >= n", "value": 140}],
57 | "type": "onePerLineAfterFirst"
58 | }
59 | ]
60 | }
61 | },
62 | "whitespace": {
63 | "arrowFunctionsPolicy": "around",
64 | "functionTypeHaxe3Policy": "around",
65 | "functionTypeHaxe4Policy": "around"
66 | }
67 | }
--------------------------------------------------------------------------------
/makeReleaseZip.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | npm install
4 | npx lix download
5 | npx lix use haxe nightly
6 |
7 | npx haxe buildAll.hxml
8 |
9 | rm -f haxe-checkstyle.zip
10 | zip -9 -r -q haxe-checkstyle.zip src run.n haxecheckstyle.js resources/sample-config.json resources/logo.png resources/codeclimate_pr.png haxelib.json hxformat.json package.json README.md CHANGELOG.md LICENSE.md
11 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@haxecheckstyle/haxe-checkstyle",
3 | "version": "2.9.0",
4 | "description": "Automated code analysis ideal for projects that want to enforce a coding standard.",
5 | "repository": {
6 | "type": "git",
7 | "url": "git+https://github.com/HaxeCheckstyle/haxe-checkstyle.git"
8 | },
9 | "keywords": [
10 | "checkstyle",
11 | "haxe",
12 | "standards",
13 | "static",
14 | "analysis",
15 | "coding",
16 | "style",
17 | "cross"
18 | ],
19 | "author": {
20 | "name": "Alexander Blum",
21 | "email": "Alexander.Blum@gmail.com"
22 | },
23 | "contributors": [
24 | {
25 | "name": "Adi Reddy Mora"
26 | },
27 | {
28 | "name": "Jens Fischer"
29 | }
30 | ],
31 | "devDependencies": {
32 | "lix": "^15.12.0",
33 | "uglify-js-es6": "^2.8.9"
34 | },
35 | "bugs": "https://github.com/HaxeCheckstyle/haxe-checkstyle/issues",
36 | "license": "MIT",
37 | "bin": {
38 | "haxe-checkstyle": "bin/checkstyle.js"
39 | },
40 | "files": [
41 | "bin"
42 | ],
43 | "publishConfig": {
44 | "registry": "https://npm.pkg.github.com/"
45 | },
46 | "scripts": {
47 | "build": "haxe buildJS.hxml && ./uglifyCheckstyle.sh"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/resources/codeclimate_pr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HaxeCheckstyle/haxe-checkstyle/77565f253c4c722cb56d793c82249c47df35c872/resources/codeclimate_pr.png
--------------------------------------------------------------------------------
/resources/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HaxeCheckstyle/haxe-checkstyle/77565f253c4c722cb56d793c82249c47df35c872/resources/icon.png
--------------------------------------------------------------------------------
/resources/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HaxeCheckstyle/haxe-checkstyle/77565f253c4c722cb56d793c82249c47df35c872/resources/logo.png
--------------------------------------------------------------------------------
/resources/logo/haxe-checkstyle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HaxeCheckstyle/haxe-checkstyle/77565f253c4c722cb56d793c82249c47df35c872/resources/logo/haxe-checkstyle.png
--------------------------------------------------------------------------------
/resources/logo/haxe-checkstyle.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HaxeCheckstyle/haxe-checkstyle/77565f253c4c722cb56d793c82249c47df35c872/resources/logo/haxe-checkstyle.xcf
--------------------------------------------------------------------------------
/resources/logo/haxe-mono.svg:
--------------------------------------------------------------------------------
1 |
2 |
60 |
--------------------------------------------------------------------------------
/resources/static-analysis.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HaxeCheckstyle/haxe-checkstyle/77565f253c4c722cb56d793c82249c47df35c872/resources/static-analysis.txt
--------------------------------------------------------------------------------
/schema/DollarName.hx:
--------------------------------------------------------------------------------
1 | enum abstract DollarName(String) to String {
2 | var DollarSchema = "$schema";
3 | var DollarRef = "$ref";
4 | }
--------------------------------------------------------------------------------
/schema/ObjectDeclField.hx:
--------------------------------------------------------------------------------
1 | #if macro
2 | import haxe.macro.Expr;
3 |
4 | #if (haxe_ver < 4.0)
5 | typedef ObjectDeclField = {
6 | var field:String;
7 | var expr:Expr;
8 | }
9 | #else
10 | typedef ObjectDeclField = haxe.macro.Expr.ObjectField;
11 | #end
12 | #end
--------------------------------------------------------------------------------
/schema/SchemaGenerator.hx:
--------------------------------------------------------------------------------
1 | import haxe.Json;
2 | import haxe.io.Path;
3 | import sys.io.File;
4 |
5 | class SchemaGenerator {
6 | public static function main() {
7 | var exludeConfig = CheckstyleSchemaGenerator.generate("checkstyle.config.ExcludeConfig",
8 | "https://raw.githubusercontent.com/HaxeCheckstyle/haxe-checkstyle/dev/resources/checkstyle-excludes-schema.json");
9 | File.saveContent(Path.join(["resources", "checkstyle-excludes-schema.json"]), Json.stringify(exludeConfig, " "));
10 |
11 | var config = CheckstyleSchemaGenerator.generate("checkstyle.config.Config",
12 | "https://raw.githubusercontent.com/HaxeCheckstyle/haxe-checkstyle/dev/resources/checkstyle-schema.json");
13 | File.saveContent(Path.join(["resources", "checkstyle-schema.json"]), Json.stringify(config, " "));
14 | }
15 | }
--------------------------------------------------------------------------------
/schema/SchemaUtils.hx:
--------------------------------------------------------------------------------
1 | #if macro
2 | import haxe.macro.Expr;
3 |
4 | class SchemaUtils {
5 | public static function makeObjectDecl(fields:Array, structInfo:Null, order:Int, pos:Position):Expr {
6 | if (order >= 0) fields.push({field: "propertyOrder", expr: macro $v{order}});
7 | if (structInfo != null && structInfo.doc != null) {
8 | fields.push({field: "description", expr: macro $v{StringTools.trim(structInfo.doc)}});
9 | }
10 | return {pos: pos, expr: EObjectDecl(fields)};
11 | }
12 |
13 | public static function makeObject(props:Expr, structInfo:Null, required:Array, order:Int, pos:Position):Expr {
14 | var fields:Array = [
15 | {field: "type", expr: macro "object"},
16 | {field: "properties", expr: props},
17 | {field: "additionalProperties", expr: macro false}
18 | ];
19 | if (required.length > 0) {
20 | var exprs:Array = [for (req in required) macro $v{req}];
21 | fields.push({field: "required", expr: macro $a{exprs}});
22 | }
23 | return makeObjectDecl(fields, structInfo, order, pos);
24 | }
25 |
26 | public static function makeEnum(enumList:Expr, structInfo:Null, order:Int, pos:Position):Expr {
27 | var fields:Array = [{field: "type", expr: macro "string"}, {field: "enum", expr: enumList}];
28 | return makeObjectDecl(fields, structInfo, order, pos);
29 | }
30 |
31 | public static function makeStructInfo(name:String, doc:String):Null {
32 | if (doc == null) return null;
33 | doc = StringTools.trim(doc);
34 | if (doc.length <= 0) return null;
35 | return {name: name, doc: StringTools.trim(doc)};
36 | }
37 | }
38 | #end
--------------------------------------------------------------------------------
/schema/StructInfo.hx:
--------------------------------------------------------------------------------
1 | typedef StructInfo = {
2 | name:String,
3 | doc:String,
4 | }
--------------------------------------------------------------------------------
/src/CheckstyleVersion.hx:
--------------------------------------------------------------------------------
1 | import haxe.Json;
2 | import sys.io.File;
3 |
4 | /**
5 | Helper class to get version info from haxelib.json
6 | **/
7 | class CheckstyleVersion {
8 | /**
9 | reads version info from haxelib.json file
10 |
11 | @return haxe.macro.Expr.ExprOf
12 | **/
13 | macro public static function getCheckstyleVersion():haxe.macro.Expr.ExprOf {
14 | #if !display
15 | try {
16 | var content:String = File.getContent("haxelib.json");
17 | var haxelib = Json.parse(content);
18 | var version:String = haxelib.version;
19 | return macro $v{version};
20 | }
21 | catch (e:Any) {
22 | var version:String = "dev";
23 | return macro $v{version};
24 | }
25 | #else
26 | var version:String = "dev";
27 | return macro $v{version};
28 | #end
29 | }
30 | }
--------------------------------------------------------------------------------
/src/checkstyle/CheckFile.hx:
--------------------------------------------------------------------------------
1 | package checkstyle;
2 |
3 | import byte.ByteData;
4 |
5 | typedef CheckFile = {
6 | var name:String;
7 | var content:ByteData;
8 | var index:Int;
9 | }
--------------------------------------------------------------------------------
/src/checkstyle/CheckerPool.hx:
--------------------------------------------------------------------------------
1 | package checkstyle;
2 |
3 | class CheckerPool {
4 | var parserQueue:ParserQueue;
5 | var templateChecker:Checker;
6 | var threads:Array;
7 |
8 | public function new(parserQueue:ParserQueue, templateChecker:Checker) {
9 | this.parserQueue = parserQueue;
10 | this.templateChecker = templateChecker;
11 | threads = [];
12 | }
13 |
14 | public function start(count:Int) {
15 | for (i in 0...count) {
16 | var thread = new CheckerThread(parserQueue);
17 | threads.push(thread);
18 | thread.start(templateChecker);
19 | }
20 | }
21 |
22 | public function isFinished():Bool {
23 | if (!parserQueue.isFinished()) return false;
24 | for (thread in threads) {
25 | if (!thread.isFinished()) return false;
26 | }
27 | return true;
28 | }
29 | }
--------------------------------------------------------------------------------
/src/checkstyle/ChecksInfo.hx:
--------------------------------------------------------------------------------
1 | package checkstyle;
2 |
3 | import checkstyle.checks.Check;
4 |
5 | class ChecksInfo {
6 | var checkInfos:Map;
7 |
8 | public function new() {
9 | checkInfos = new Map();
10 |
11 | var checksClasses = CompileTime.getAllClasses(Check);
12 |
13 | for (cl in checksClasses) {
14 | if (ignoreClass(cl)) continue;
15 | var names:Array = getCheckNameFromClass(cl);
16 | for (i in 0...names.length) {
17 | var desc = getCheckDescription(cl);
18 | checkInfos[names[i]] = {
19 | name: names[i],
20 | clazz: cl,
21 | isAlias: i > 0,
22 | description: (i == 0) ? desc : desc + " [DEPRECATED, use " + names[0] + " instead]"
23 | };
24 | }
25 | }
26 | }
27 |
28 | static function ignoreClass(cl:Class):Bool {
29 | var meta = haxe.rtti.Meta.getType(cl);
30 | return (meta.ignore != null);
31 | }
32 |
33 | static function getCheckNameFromClass(cl:Class):Array {
34 | var meta = haxe.rtti.Meta.getType(cl);
35 | if (meta.name == null) throw '${Type.getClassName(cl)} has no @name meta.';
36 | return meta.name;
37 | }
38 |
39 | public static function getCheckName(check:Check):String {
40 | return getCheckNameFromClass(Type.getClass(check))[0];
41 | }
42 |
43 | function getCheckDescription(cl:Class):String {
44 | return haxe.rtti.Meta.getType(cl).desc[0];
45 | }
46 |
47 | public function checks():Iterator {
48 | return checkInfos.iterator();
49 | }
50 |
51 | public function build(name:String):Check {
52 | if (!checkInfos.exists(name)) return null;
53 | var cl = checkInfos[name].clazz;
54 | return cast Type.createInstance(cl, []);
55 | }
56 | }
57 |
58 | typedef CheckInfo = {
59 | var name:String;
60 | var description:String;
61 | var clazz:Class;
62 | var isAlias:Bool;
63 | }
--------------------------------------------------------------------------------
/src/checkstyle/Message.hx:
--------------------------------------------------------------------------------
1 | package checkstyle;
2 |
3 | import checkstyle.checks.Category;
4 |
5 | typedef Message = MessageLocation & {
6 | var message:String;
7 | @:optional var code:String;
8 | var desc:String;
9 | var severity:SeverityLevel;
10 | var moduleName:String;
11 | var categories:Array;
12 | var points:Int;
13 | var related:Array;
14 | };
15 |
16 | typedef MessageLocation = {
17 | var fileName:String;
18 | var range:MessageRange;
19 | };
20 |
21 | typedef MessageRange = {
22 | var start:MessagePosition;
23 | var end:MessagePosition;
24 | };
25 |
26 | typedef MessagePosition = {
27 | var line:Int;
28 | var column:Int;
29 | };
--------------------------------------------------------------------------------
/src/checkstyle/ParserQueue.hx:
--------------------------------------------------------------------------------
1 | package checkstyle;
2 |
3 | import checkstyle.utils.Mutex;
4 | import checkstyle.utils.Thread;
5 |
6 | class ParserQueue {
7 | static inline var SLEEP_TIME:Float = 0.1;
8 |
9 | var files:Array;
10 | var checkers:Array;
11 | var finished:Bool;
12 | var lock:Mutex;
13 | var templateChecker:Checker;
14 | var maxPreparse:Int;
15 |
16 | public function new(files:Array, templateChecker:Checker) {
17 | this.files = files;
18 | this.templateChecker = templateChecker;
19 | lock = new Mutex();
20 | }
21 |
22 | public function start(max:Int) {
23 | if (max <= 0) max = 1;
24 | maxPreparse = max;
25 | checkers = [];
26 | Thread.create(runParser);
27 | }
28 |
29 | function runParser() {
30 | finished = false;
31 | while (files.length > 0) {
32 | if (checkers.length > maxPreparse) {
33 | Sys.sleep(SLEEP_TIME);
34 | continue;
35 | }
36 | var file = files.shift();
37 | var checker:Checker = new Checker();
38 | checker.baseDefines = templateChecker.baseDefines;
39 | checker.defineCombinations = templateChecker.defineCombinations;
40 | checker.verbose = templateChecker.verbose;
41 | checker.loadFileContent(file);
42 | if (!checker.createContext(file)) {
43 | checker.unloadFileContent(file);
44 | continue;
45 | }
46 |
47 | lock.acquire();
48 | checkers.push(checker);
49 | lock.release();
50 | }
51 | finished = true;
52 | }
53 |
54 | public function isFinished():Bool {
55 | if (checkers.length > 0) return false;
56 | return finished;
57 | }
58 |
59 | public function nextFile():Checker {
60 | var checkFile:Checker = null;
61 | lock.acquire();
62 | if (checkers.length > 0) {
63 | checkFile = checkers.shift();
64 | }
65 | lock.release();
66 | return checkFile;
67 | }
68 | }
--------------------------------------------------------------------------------
/src/checkstyle/SeverityLevel.hx:
--------------------------------------------------------------------------------
1 | package checkstyle;
2 |
3 | /**
4 | sets gravity of reported violations:
5 | - IGNORE = do not report violations, violations do not appear anywhere in output
6 | - INFO = all violations have info / lowest priority
7 | - WARNING = all violations have warning / medium priority
8 | - ERROR = all violations have error / highest priority
9 | **/
10 | enum abstract SeverityLevel(String) from String {
11 | var INFO = "INFO";
12 | var WARNING = "WARNING";
13 | var ERROR = "ERROR";
14 | var IGNORE = "IGNORE";
15 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/Category.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks;
2 |
3 | enum abstract Category(String) {
4 | var BUG_RISK = "Bug Risk";
5 | var CLARITY = "Clarity";
6 | var COMPLEXITY = "Complexity";
7 | var DUPLICATION = "Duplication";
8 | var STYLE = "Style";
9 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/block/BlockBreakingConditionalCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.block;
2 |
3 | /**
4 | Checks for block breaking conditionals
5 | **/
6 | @name("BlockBreakingConditional")
7 | @desc("Checks for block breaking conditionals.")
8 | class BlockBreakingConditionalCheck extends Check {
9 | public function new() {
10 | super(TOKEN);
11 | }
12 |
13 | override function actualRun() {
14 | var root:TokenTree = checker.getTokenTree();
15 | var allBrs:Array = root.filterCallback(function(token:TokenTree, index:Int):FilterResult {
16 | return switch (token.tok) {
17 | case BrOpen | BrClose:
18 | FoundGoDeeper;
19 | default:
20 | GoDeeper;
21 | }
22 | });
23 |
24 | for (br in allBrs) {
25 | if (isPosSuppressed(br.pos)) continue;
26 | switch (br.tok) {
27 | case BrOpen:
28 | if (br.access().firstOf(BrClose).exists()) continue;
29 | logPos("Left curly has no matching right curly", br.pos);
30 | case BrClose:
31 | if (br.access().parent().matches(BrOpen).exists()) continue;
32 | logPos("Right curly has no matching left curly", br.pos);
33 | default:
34 | continue;
35 | }
36 | }
37 | }
38 |
39 | override public function detectableInstances():DetectableInstances {
40 | return [{
41 | fixed: [],
42 | properties: [{
43 | propertyName: "severity",
44 | values: [SeverityLevel.INFO]
45 | }]
46 | }];
47 | }
48 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/coding/AvoidTernaryOperatorCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | /**
4 | Detects ternary operators. Useful for developers who find ternary operators hard to read and want forbid them.
5 | **/
6 | @name("AvoidTernaryOperator", "AvoidInlineConditionals")
7 | @desc("Detects ternary operators. Useful for developers who find ternary operators hard to read and want forbid them.")
8 | class AvoidTernaryOperatorCheck extends Check {
9 | public function new() {
10 | super(AST);
11 | severity = SeverityLevel.IGNORE;
12 | categories = [Category.COMPLEXITY];
13 | points = 3;
14 | }
15 |
16 | override function actualRun() {
17 | if (checker.ast == null) return;
18 | checker.ast.walkFile(function(e:Expr) {
19 | if (isPosSuppressed(e.pos)) return;
20 | switch (e.expr) {
21 | case ETernary(econd, eif, eelse):
22 | logPos("Avoid ternary operator", e.pos);
23 | default:
24 | }
25 | });
26 | }
27 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/coding/DefaultComesLastCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | /**
4 | Check that the "default" is after all the cases in a "switch" statement. Haxe allows "default" anywhere within the "switch" statement.
5 | But it is more readable if it comes after the last "case".
6 | **/
7 | @name("DefaultComesLast")
8 | @desc("Check that the `default` is after all the cases in a `switch` statement. Haxe allows `default` anywhere within the `switch` statement. But it is more readable if it comes after the last `case`.")
9 | class DefaultComesLastCheck extends Check {
10 | public function new() {
11 | super(TOKEN);
12 | categories = [Category.STYLE, Category.CLARITY];
13 | points = 2;
14 | }
15 |
16 | override function actualRun() {
17 | var root:TokenTree = checker.getTokenTree();
18 | var acceptableTokens:Array = root.filterCallback(function(token:TokenTree, index:Int):FilterResult {
19 | return switch (token.tok) {
20 | case Kwd(KwdSwitch):
21 | FoundGoDeeper;
22 | default:
23 | GoDeeper;
24 | }
25 | });
26 |
27 | for (token in acceptableTokens) {
28 | var tokens:Array = token.filterCallback(function(token:TokenTree, index:Int):FilterResult {
29 | return switch (token.tok) {
30 | case Kwd(KwdCase) | Kwd(KwdDefault):
31 | FoundSkipSubtree;
32 | default:
33 | GoDeeper;
34 | }
35 | });
36 | if (tokens.length <= 0) continue;
37 | if (tokens[tokens.length - 1].matches(Kwd(KwdDefault))) continue;
38 |
39 | for (i in 0...tokens.length) {
40 | if (tokens[i].matches(Kwd(KwdDefault)) && i < tokens.length - 1) {
41 | logPos('Default should be last label in the "switch"', token.pos);
42 | continue;
43 | }
44 | }
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/coding/MagicNumberCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | /**
4 | Checks that there are no magic numbers. By default, -1, 0, 1, and 2 are not considered to be magic numbers.
5 | **/
6 | @name("MagicNumber")
7 | @desc("Checks that there are no magic numbers. By default, -1, 0, 1, and 2 are not considered to be magic numbers.")
8 | class MagicNumberCheck extends Check {
9 | /**
10 | list of magic numbers to ignore during checks
11 | **/
12 | public var ignoreNumbers:Array;
13 |
14 | public function new() {
15 | super(TOKEN);
16 | ignoreNumbers = [-1, 0, 1, 2];
17 | categories = [Category.CLARITY, Category.COMPLEXITY];
18 | points = 3;
19 | }
20 |
21 | override function actualRun() {
22 | var root:TokenTree = checker.getTokenTree();
23 | var allTypes:Array = root.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
24 | return switch (token.tok) {
25 | case Kwd(KwdAbstract) | Kwd(KwdClass) | Kwd(KwdEnum) | Kwd(KwdInterface) | Kwd(KwdTypedef):
26 | FoundSkipSubtree;
27 | default:
28 | GoDeeper;
29 | }
30 | });
31 | for (type in allTypes) {
32 | if (TokenTreeCheckUtils.isTypeEnumAbstract(type)) continue;
33 | checkForNumbers(type);
34 | }
35 | }
36 |
37 | function checkForNumbers(parent:TokenTree) {
38 | var allNumbers:Array = parent.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
39 | return switch (token.tok) {
40 | case Const(CInt(_)): FoundGoDeeper;
41 | case Const(CFloat(_)): FoundGoDeeper;
42 | default: GoDeeper;
43 | }
44 | });
45 |
46 | for (numberToken in allNumbers) {
47 | if (isPosSuppressed(numberToken.pos)) continue;
48 | if (filterNumber(numberToken)) continue;
49 | switch (numberToken.tok) {
50 | case Const(CInt(n, s)):
51 | var number:Int = Std.parseInt(n.replace("_", ""));
52 | if (ignoreNumbers.contains(number)) continue;
53 | if (s == null) s = "";
54 | logPos('"$n$s" is a magic number', numberToken.pos);
55 | case Const(CFloat(n, s)):
56 | var number:Float = Std.parseFloat(n.replace("_", ""));
57 | if (ignoreNumbers.contains(number)) continue;
58 | if (s == null) s = "";
59 | logPos('"$n$s" is a magic number', numberToken.pos);
60 | default:
61 | }
62 | }
63 | }
64 |
65 | function filterNumber(token:TokenTree):Bool {
66 | if ((token == null) || (token.tok == Root)) return false;
67 | return switch (token.tok) {
68 | case At: true;
69 | case Kwd(KwdFinal): true;
70 | case BrOpen: false;
71 | case Kwd(KwdVar): if (token.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
72 | return switch (token.tok) {
73 | case Kwd(KwdStatic):
74 | FoundSkipSubtree;
75 | default:
76 | GoDeeper;
77 | }
78 | }).length > 0) {
79 | true;
80 | }
81 | else {
82 | false;
83 | }
84 | default: filterNumber(token.parent);
85 | }
86 | }
87 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/coding/MultipleVariableDeclarationsCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | /**
4 | Checks that each variable declaration is in its own statement and on its own line.
5 | **/
6 | @name("MultipleVariableDeclarations")
7 | @desc("Checks that each variable declaration is in its own statement and on its own line.")
8 | class MultipleVariableDeclarationsCheck extends Check {
9 | public function new() {
10 | super(TOKEN);
11 | categories = [Category.STYLE, Category.CLARITY, Category.COMPLEXITY];
12 | points = 2;
13 | }
14 |
15 | override function actualRun() {
16 | var root:TokenTree = checker.getTokenTree();
17 | var acceptableTokens:Array = root.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
18 | return switch (token.tok) {
19 | case Kwd(KwdVar):
20 | FoundGoDeeper;
21 | default:
22 | GoDeeper;
23 | }
24 | });
25 |
26 | var lastVarLineNo = -1;
27 | for (v in acceptableTokens) {
28 | var curVarLineNo = checker.getLinePos(v.pos.min).line;
29 | if (lastVarLineNo > 0 && lastVarLineNo == curVarLineNo) logPos("Only one variable definition per line allowed", v.pos);
30 | lastVarLineNo = curVarLineNo;
31 | var count = 0;
32 | for (c in v.children) {
33 | switch (c.tok) {
34 | case Const(CIdent(name)):
35 | count++;
36 | default:
37 | }
38 | }
39 | if (count > 1) logPos("Each variable declaration must be in its own statement", v.pos);
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/coding/NestedControlFlowCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | /**
4 | Checks for maximium nesting depth of control flow expressions (`if`, `for`, `while`, `do/while`, `switch` and `try`).
5 | **/
6 | @name("NestedControlFlow")
7 | @desc("Checks for maximium nesting depth of control flow expressions (`if`, `for`, `while`, `do/while`, `switch` and `try`).")
8 | class NestedControlFlowCheck extends Check {
9 | /**
10 | maximum number of nested control flow expressions allowed
11 | **/
12 | public var max:Int;
13 |
14 | public function new() {
15 | super(TOKEN);
16 | max = 3;
17 | categories = [Category.COMPLEXITY];
18 | points = 8;
19 | }
20 |
21 | override function actualRun() {
22 | var root:TokenTree = checker.getTokenTree();
23 | var controlFlowTokens:Array = root.filterCallback(function(token:TokenTree, index:Int):FilterResult {
24 | return switch (token.tok) {
25 | case Kwd(KwdFor):
26 | FoundGoDeeper;
27 | case Kwd(KwdIf):
28 | FoundGoDeeper;
29 | case Kwd(KwdSwitch):
30 | FoundGoDeeper;
31 | case Kwd(KwdDo):
32 | FoundGoDeeper;
33 | case Kwd(KwdWhile):
34 | if ((token.parent != null) && (token.parent.matches(Kwd(KwdDo)))) GoDeeper; else FoundGoDeeper;
35 | case Kwd(KwdTry):
36 | FoundGoDeeper;
37 | default:
38 | GoDeeper;
39 | }
40 | });
41 | for (token in controlFlowTokens) {
42 | if (isPosSuppressed(token.pos)) continue;
43 | checkExpressionDepth(token);
44 | }
45 | }
46 |
47 | function checkExpressionDepth(token:TokenTree) {
48 | var depth:Int = calcDepth(token);
49 | if (depth > max) warnNestedDepth(depth, token.getPos());
50 | }
51 |
52 | function calcDepth(token:TokenTree):Int {
53 | var parent:TokenTree = token.parent;
54 | var count:Int = 1;
55 | while ((parent != null) && (parent.tok != Root)) {
56 | switch (parent.tok) {
57 | case Kwd(KwdFor):
58 | count++;
59 | case Kwd(KwdIf):
60 | count++;
61 | case Kwd(KwdSwitch):
62 | count++;
63 | case Kwd(KwdDo):
64 | count++;
65 | case Kwd(KwdWhile):
66 | if ((parent.parent == null) || (!parent.parent.matches(Kwd(KwdDo)))) count++;
67 | case Kwd(KwdTry):
68 | count++;
69 | default:
70 | }
71 | parent = parent.parent;
72 | }
73 | return count;
74 | }
75 |
76 | function warnNestedDepth(depth:Int, pos:Position) {
77 | logPos('Nested control flow depth is $depth (max allowed is ${max})', pos);
78 | }
79 |
80 | override public function detectableInstances():DetectableInstances {
81 | return [{
82 | fixed: [],
83 | properties: [{
84 | propertyName: "max",
85 | values: [for (i in 1...5) i]
86 | }]
87 | }];
88 | }
89 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/coding/NestedForDepthCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | /**
4 | Restricts nested loop blocks to a specified depth (default = 1).
5 | **/
6 | @name("NestedForDepth")
7 | @desc("Restricts nested loop blocks to a specified depth (default = 1).")
8 | class NestedForDepthCheck extends Check {
9 | /**
10 | maximum number of nested loops allowed
11 | setting "max" to 1 allows one inner loop
12 | **/
13 | public var max:Int;
14 |
15 | public function new() {
16 | super(AST);
17 | max = 1;
18 | categories = [Category.COMPLEXITY];
19 | points = 8;
20 | }
21 |
22 | override function actualRun() {
23 | forEachField(function(f, _) {
24 | switch (f.kind) {
25 | case FFun(fun):
26 | scanBlock(fun.expr, -1);
27 | default:
28 | }
29 | });
30 | }
31 |
32 | function scanBlock(e:Expr, depth:Int) {
33 | if (e == null) return;
34 | if (depth > max) {
35 | warnNestedForDepth(depth, e.pos);
36 | return;
37 | }
38 | switch (e.expr) {
39 | case EBlock(exprs):
40 | scanExprs(exprs, depth);
41 | default:
42 | }
43 | }
44 |
45 | function scanExprs(exprs:Array, depth:Int) {
46 | for (e in exprs) {
47 | switch (e.expr) {
48 | case EFor(_, expr):
49 | scanBlock(expr, depth + 1);
50 | case EWhile(_, expr, _):
51 | scanBlock(expr, depth + 1);
52 | default:
53 | }
54 | }
55 | }
56 |
57 | function warnNestedForDepth(depth:Int, pos:Position) {
58 | logPos('Nested loop depth is $depth (max allowed is ${max})', pos);
59 | }
60 |
61 | override public function detectableInstances():DetectableInstances {
62 | return [{
63 | fixed: [],
64 | properties: [{
65 | propertyName: "max",
66 | values: [for (i in 0...5) i]
67 | }]
68 | }];
69 | }
70 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/coding/NestedIfDepthCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | /**
4 | Restricts nested "if-else" blocks to a specified depth (default = 1).
5 | **/
6 | @name("NestedIfDepth")
7 | @desc("Restricts nested `if-else` blocks to a specified depth (default = 1).")
8 | class NestedIfDepthCheck extends Check {
9 | /**
10 | maximum number of nested if statements allowed
11 | setting "max" to 1 allows one if inside another
12 | **/
13 | public var max:Int;
14 |
15 | public function new() {
16 | super(AST);
17 | max = 1;
18 | categories = [Category.COMPLEXITY];
19 | points = 8;
20 | }
21 |
22 | override function actualRun() {
23 | forEachField(function(f, _) {
24 | switch (f.kind) {
25 | case FFun(fun):
26 | scanBlock(fun.expr, -1);
27 | default:
28 | }
29 | });
30 | }
31 |
32 | function scanBlock(e:Expr, depth:Int) {
33 | if (e == null) return;
34 | if (depth > max) {
35 | warnNestedIfDepth(depth, e.pos);
36 | return;
37 | }
38 | switch (e.expr) {
39 | case EBlock(exprs):
40 | scanExprs(exprs, depth);
41 | default:
42 | }
43 | }
44 |
45 | function scanExprs(exprs:Array, depth:Int) {
46 | for (e in exprs) {
47 | switch (e.expr) {
48 | case EIf(_, ifPart, elsePart):
49 | scanBlock(ifPart, depth + 1);
50 | scanBlock(elsePart, depth + 1);
51 | default:
52 | }
53 | }
54 | }
55 |
56 | function warnNestedIfDepth(depth:Int, pos:Position) {
57 | logPos('Nested if-else depth is $depth (max allowed is ${max})', pos);
58 | }
59 |
60 | override public function detectableInstances():DetectableInstances {
61 | return [{
62 | fixed: [],
63 | properties: [{
64 | propertyName: "max",
65 | values: [for (i in 0...10) i]
66 | }]
67 | }];
68 | }
69 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/coding/NestedTryDepthCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | /**
4 | Restricts nested "try" blocks to a specified depth (default = 1).
5 | **/
6 | @name("NestedTryDepth")
7 | @desc("Restricts nested `try` blocks to a specified depth (default = 1).")
8 | class NestedTryDepthCheck extends Check {
9 | /**
10 | maximum number of nested try/catch statemenmts allowed
11 | setting "max" to 1 allows one inner try/catch
12 | **/
13 | public var max:Int;
14 |
15 | public function new() {
16 | super(AST);
17 | max = 1;
18 | categories = [Category.COMPLEXITY];
19 | points = 5;
20 | }
21 |
22 | override function actualRun() {
23 | forEachField(function(f, _) {
24 | switch (f.kind) {
25 | case FFun(fun):
26 | scanBlock(fun.expr, -1);
27 | default:
28 | }
29 | });
30 | }
31 |
32 | function scanBlock(e:Expr, depth:Int) {
33 | if (e == null) return;
34 | if (depth > max) {
35 | warnNestedTryDepth(depth, e.pos);
36 | return;
37 | }
38 | switch (e.expr) {
39 | case EBlock(exprs):
40 | scanExprs(exprs, depth);
41 | default:
42 | }
43 | }
44 |
45 | function scanExprs(exprs:Array, depth:Int) {
46 | for (e in exprs) {
47 | switch (e.expr) {
48 | case ETry(expr, catches):
49 | scanBlock(expr, depth + 1);
50 | scanCatches(catches, depth + 1);
51 | default:
52 | }
53 | }
54 | }
55 |
56 | function scanCatches(catches:Array, depth:Int) {
57 | for (c in catches) {
58 | scanBlock(c.expr, depth);
59 | }
60 | }
61 |
62 | function warnNestedTryDepth(depth:Int, pos:Position) {
63 | logPos('Nested try depth is $depth (max allowed is ${max})', pos);
64 | }
65 |
66 | override public function detectableInstances():DetectableInstances {
67 | return [{
68 | fixed: [],
69 | properties: [{
70 | propertyName: "max",
71 | values: [for (i in 0...5) i]
72 | }]
73 | }];
74 | }
75 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/coding/NullableParameterCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | using haxe.macro.ExprTools;
4 |
5 | /**
6 | Enforces a style for nullable parameters.
7 | **/
8 | @name("NullableParameter")
9 | @desc("Enforces a style for nullable parameters.")
10 | class NullableParameterCheck extends Check {
11 | /**
12 | nullable style to enforece
13 | - questionMark = nullable parameters should use "?name:Type"
14 | - nullDefault = nullable parameters should use "name:Type = null"
15 | **/
16 | public var option:NullableParameterCheckOption;
17 |
18 | public function new() {
19 | super(AST);
20 | option = QUESTION_MARK;
21 | }
22 |
23 | override function actualRun() {
24 | forEachField(function(field, _) {
25 | switch (field.kind) {
26 | case FFun(f):
27 | for (arg in f.args) checkArgument(arg, field.pos);
28 | case _:
29 | }
30 | });
31 | }
32 |
33 | function checkArgument(arg:FunctionArg, pos:Position) {
34 | var hasNullDefault = arg.value.toString() == "null";
35 | if (!hasNullDefault && arg.value != null) return;
36 | var formatted = formatArguments(arg.opt, arg.name, hasNullDefault);
37 |
38 | switch (option) {
39 | case QUESTION_MARK:
40 | if (hasNullDefault) logRange('Function parameter $formatted should be ${formatArguments(true, arg.name, false)}', pos.min, pos.min);
41 | case NULL_DEFAULT:
42 | if (arg.opt) logRange('Function parameter $formatted should be ${formatArguments(false, arg.name, true)}', pos.min, pos.min);
43 | }
44 | }
45 |
46 | function formatArguments(opt:Bool, name:String, nullDefault:Bool):String {
47 | return '"' + (opt ? "?" : "") + name + (nullDefault ? " = null" : "") + '"';
48 | }
49 |
50 | override public function detectableInstances():DetectableInstances {
51 | return [{
52 | fixed: [],
53 | properties: [{
54 | propertyName: "option",
55 | values: [QUESTION_MARK, NULL_DEFAULT]
56 | }]
57 | }];
58 | }
59 | }
60 |
61 | /**
62 | - questionMark = nullable parameters should use "?name:Type"
63 | - nullDefault = nullable parameters should use "name:Type = null"
64 | **/
65 | enum abstract NullableParameterCheckOption(String) {
66 | var QUESTION_MARK = "questionMark";
67 | var NULL_DEFAULT = "nullDefault";
68 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/coding/ReturnCountCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | import checkstyle.utils.PosHelper;
4 |
5 | /**
6 | Restricts the number of return statements in methods (2 by default). Ignores methods that matches "ignoreFormat" regex property.
7 | **/
8 | @name("ReturnCount")
9 | @desc("Restricts the number of return statements in methods (2 by default). Ignores methods that matches `ignoreFormat` regex property.")
10 | class ReturnCountCheck extends Check {
11 | /**
12 | maximum number of return calls a function may have
13 | **/
14 | public var max:Int;
15 |
16 | /**
17 | ignore function names matching "ignoreFormat" regex
18 | **/
19 | public var ignoreFormat:String;
20 |
21 | public function new() {
22 | super(TOKEN);
23 | max = 2;
24 | ignoreFormat = "^$";
25 | categories = [Category.COMPLEXITY];
26 | points = 5;
27 | }
28 |
29 | override function actualRun() {
30 | var ignoreFormatRE:EReg = new EReg(ignoreFormat, "");
31 | var root:TokenTree = checker.getTokenTree();
32 | var functions = root.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
33 | return switch (token.tok) {
34 | case Kwd(KwdFunction):
35 | FoundGoDeeper;
36 | default:
37 | GoDeeper;
38 | }
39 | });
40 | for (fn in functions) {
41 | if (fn.children == null) continue;
42 | switch (fn.getFirstChild().tok) {
43 | case Const(CIdent(name)):
44 | if (ignoreFormatRE.match(name)) continue;
45 | default:
46 | }
47 | if (isPosSuppressed(fn.pos)) continue;
48 | if (!fn.hasChildren()) continue;
49 | var returns = fn.filterCallback(filterReturns);
50 | if (returns.length > max) {
51 | logPos('Return count is ${returns.length} (max allowed is ${max})', PosHelper.getReportPos(fn));
52 | }
53 | }
54 | }
55 |
56 | function filterReturns(token:TokenTree, depth:Int):FilterResult {
57 | return switch (token.tok) {
58 | case Kwd(KwdFunction):
59 | // top node is always a function node
60 | if (depth == 0) GoDeeper; else SkipSubtree;
61 | case Kwd(KwdReturn): FoundSkipSubtree;
62 | default: GoDeeper;
63 | }
64 | }
65 |
66 | override public function detectableInstances():DetectableInstances {
67 | return [{
68 | fixed: [],
69 | properties: [{
70 | propertyName: "max",
71 | values: [for (i in 2...20) i]
72 | }]
73 | }];
74 | }
75 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/coding/SimplifyBooleanExpressionCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | /**
4 | Checks for over-complicated boolean expressions. Finds code like "if (b == true), b || true, !false", etc.
5 | **/
6 | @name("SimplifyBooleanExpression")
7 | @desc("Checks for over-complicated boolean expressions. Finds code like `if (b == true), b || true, !false`, etc.")
8 | class SimplifyBooleanExpressionCheck extends Check {
9 | public function new() {
10 | super(TOKEN);
11 | categories = [Category.COMPLEXITY];
12 | points = 3;
13 | }
14 |
15 | override function actualRun() {
16 | var root:TokenTree = checker.getTokenTree();
17 | var acceptableTokens:Array = root.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
18 | return switch (token.tok) {
19 | case Kwd(KwdTrue) | Kwd(KwdFalse) | Binop(OpEq) | Binop(OpNotEq) | Unop(OpNot) | Binop(OpOr) | Binop(OpAnd) | Binop(OpBoolOr) |
20 | Binop(OpBoolAnd):
21 | FoundGoDeeper;
22 | default:
23 | GoDeeper;
24 | }
25 | });
26 |
27 | for (token in acceptableTokens) {
28 | if (isPosSuppressed(token.pos)) continue;
29 | if (token.matches(Kwd(KwdTrue)) || token.matches(Kwd(KwdFalse))) checkToken(token);
30 | }
31 | }
32 |
33 | function checkToken(token:TokenTree) {
34 | var parent = token.parent;
35 | switch (parent.tok) {
36 | case Binop(OpEq), Binop(OpNotEq), Unop(OpNot), Binop(OpOr), Binop(OpAnd), Binop(OpBoolOr), Binop(OpBoolAnd):
37 | logPos("Boolean expression can be simplified", token.pos);
38 | default:
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/coding/SimplifyBooleanReturnCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | /**
4 | Checks for over-complicated boolean return statements.
5 | **/
6 | @name("SimplifyBooleanReturn")
7 | @desc("Checks for over-complicated boolean return statements.")
8 | class SimplifyBooleanReturnCheck extends Check {
9 | public function new() {
10 | super(TOKEN);
11 | categories = [Category.COMPLEXITY];
12 | points = 2;
13 | }
14 |
15 | override function actualRun() {
16 | var root:TokenTree = checker.getTokenTree();
17 | var acceptableTokens:Array = root.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
18 | return switch (token.tok) {
19 | case Kwd(KwdIf):
20 | FoundGoDeeper;
21 | default:
22 | GoDeeper;
23 | }
24 | });
25 |
26 | for (token in acceptableTokens) {
27 | var elseLiteral = token.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
28 | return switch (token.tok) {
29 | case Kwd(KwdElse):
30 | FoundSkipSubtree;
31 | default:
32 | GoDeeper;
33 | }
34 | })[0];
35 | if (elseLiteral == null) continue;
36 |
37 | var elseStatement = elseLiteral.getFirstChild();
38 | var thenStatement = token.children[1];
39 |
40 | if (canReturnOnlyBooleanLiteral(thenStatement) && canReturnOnlyBooleanLiteral(elseStatement)) {
41 | logPos("Conditional logic can be removed", token.pos);
42 | }
43 | }
44 | }
45 |
46 | function canReturnOnlyBooleanLiteral(tkn:TokenTree):Bool {
47 | if (isBooleanLiteralReturnStatement(tkn)) return true;
48 | return isBooleanLiteralReturnStatement(tkn.getFirstChild());
49 | }
50 |
51 | function isBooleanLiteralReturnStatement(tkn:TokenTree):Bool {
52 | var booleanReturnStatement = false;
53 | if (tkn != null && tkn.matches(Kwd(KwdReturn))) {
54 | var expr = tkn.getFirstChild();
55 | booleanReturnStatement = isBooleanLiteralType(expr);
56 | }
57 | return booleanReturnStatement;
58 | }
59 |
60 | function isBooleanLiteralType(tkn:TokenTree):Bool {
61 | return tkn.matches(Kwd(KwdTrue)) || tkn.matches(Kwd(KwdFalse));
62 | }
63 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/coding/TraceCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | /**
4 | Checks for trace calls in code.
5 | **/
6 | @name("Trace")
7 | @desc("Checks for trace calls in code.")
8 | class TraceCheck extends Check {
9 | public function new() {
10 | super(TOKEN);
11 | severity = SeverityLevel.IGNORE;
12 | }
13 |
14 | override function actualRun() {
15 | var root:TokenTree = checker.getTokenTree();
16 | var traces = root.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
17 | return switch (token.tok) {
18 | case Const(CIdent("trace")):
19 | FoundGoDeeper;
20 | default:
21 | GoDeeper;
22 | }
23 | });
24 | for (tr in traces) {
25 | if (!tr.getFirstChild().tok.match(POpen)) continue;
26 | if (filterTrace(tr.parent)) continue;
27 | if (isPosSuppressed(tr.pos)) continue;
28 |
29 | logPos("Trace detected", tr.getPos());
30 | }
31 | }
32 |
33 | function filterTrace(token:TokenTree):Bool {
34 | return switch (token.tok) {
35 | case Dot: true;
36 | case Kwd(KwdFunction): true;
37 | default: false;
38 | }
39 | }
40 |
41 | override public function detectableInstances():DetectableInstances {
42 | return [{
43 | fixed: [],
44 | properties: [{
45 | propertyName: "severity",
46 | values: [SeverityLevel.INFO]
47 | }]
48 | }];
49 | }
50 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/coding/VariableInitialisationCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | /**
4 | Checks for instance variables that are initialised at class level.
5 | **/
6 | @name("VariableInitialisation")
7 | @desc("Checks for instance variables that are initialised at class level.")
8 | class VariableInitialisationCheck extends Check {
9 | /**
10 | final fields must be initialised either immediately or in constructor
11 | when allowFinal is true then VariableInitialisation won't complain about initialisation at class level for final fields
12 | **/
13 | public var allowFinal:Bool;
14 |
15 | public function new() {
16 | super(AST);
17 | categories = [Category.STYLE, Category.CLARITY];
18 | points = 2;
19 | allowFinal = false;
20 | }
21 |
22 | override function actualRun() {
23 | forEachField(checkField);
24 | }
25 |
26 | function checkField(f:Field, p:ParentType) {
27 | if (f.isConstructor() || p.kind == INTERFACE || p.kind == ENUM_ABSTRACT) return;
28 |
29 | var isPrivate = false;
30 | var isPublic = false;
31 | var isInline = f.access.contains(AInline);
32 | var isStatic = f.access.contains(AStatic);
33 | var isFinal = false;
34 |
35 | if (isInline || isStatic) return;
36 |
37 | if (f.access.contains(APublic)) isPublic = true;
38 | else isPrivate = true;
39 |
40 | if (f.access.contains(AFinal)) isFinal = true;
41 | if (allowFinal && isFinal) return;
42 |
43 | if (isPrivate || isPublic) {
44 | switch (f.kind) {
45 | case FVar(t, e):
46 | if (e == null) return;
47 | warnVarInit(f.name, f.pos);
48 | case _:
49 | }
50 | }
51 | }
52 |
53 | function warnVarInit(name:String, pos:Position) {
54 | logPos('Invalid variable initialisation for "${name}" (move initialisation to constructor or function)', pos);
55 | }
56 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/comments/TODOCommentCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.comments;
2 |
3 | /**
4 | A check for TODO/FIXME/HACK/XXX/BUG comments. The format can be customised by changing `format` property.
5 | **/
6 | @name("TODOComment")
7 | @desc("A check for TODO/FIXME/HACK/XXX/BUG comments. The format can be customised by changing `format` property.")
8 | class TODOCommentCheck extends Check {
9 | /**
10 | regex todo comment format, defaults to "^\\s*(TODO|FIXME|HACK|XXX|BUG)"
11 | **/
12 | public var format:String;
13 |
14 | public function new() {
15 | super(LINE);
16 | severity = SeverityLevel.IGNORE;
17 | format = "^\\s*(TODO|FIXME|HACK|XXX|BUG)";
18 | categories = [Category.BUG_RISK];
19 | points = 8;
20 | }
21 |
22 | override function actualRun() {
23 | var re = new EReg(format, "");
24 | for (tk in checker.tokens) {
25 | switch (tk.tok) {
26 | case Comment(s) | CommentLine(s):
27 | if (re.match(s)) logPos("TODO comment:" + s, tk.pos);
28 | default:
29 | }
30 | }
31 | }
32 |
33 | override public function detectableInstances():DetectableInstances {
34 | return [{
35 | fixed: [],
36 | properties: [{
37 | propertyName: "format",
38 | values: ["^\\s*(TODO|FIXME|HACK|XXX|BUG)"]
39 | }]
40 | }];
41 | }
42 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/design/EmptyPackageCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.design;
2 |
3 | /**
4 | Checks for empty package names.
5 | **/
6 | @name("EmptyPackage")
7 | @desc("Checks for empty package names.")
8 | class EmptyPackageCheck extends Check {
9 | /**
10 | enforce using a package declaration, even if it is empty
11 | **/
12 | public var enforceEmptyPackage:Bool;
13 |
14 | public function new() {
15 | super(TOKEN);
16 | enforceEmptyPackage = false;
17 | }
18 |
19 | override function actualRun() {
20 | var root:TokenTree = checker.getTokenTree();
21 | var packageTokens = root.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
22 | return switch (token.tok) {
23 | case Kwd(KwdPackage):
24 | FoundSkipSubtree;
25 | case Kwd(_):
26 | SkipSubtree;
27 | default:
28 | GoDeeper;
29 | }
30 | });
31 | if (enforceEmptyPackage) {
32 | if (packageTokens.length == 0) log("Missing package declaration", 1, 0, 1, 0, MISSING_PACKAGE);
33 | }
34 | else checkPackageNames(packageTokens);
35 | }
36 |
37 | function checkPackageNames(entries:Array) {
38 | for (entry in entries) {
39 | var firstChild = entry.getFirstChild();
40 | if (firstChild.matches(Semicolon)) logRange("Found empty package", entry.pos.min, firstChild.pos.max, REDUNDANT_PACKAGE);
41 | }
42 | }
43 |
44 | override public function detectableInstances():DetectableInstances {
45 | return [{
46 | fixed: [],
47 | properties: [{
48 | propertyName: "enforceEmptyPackage",
49 | values: [true, false]
50 | }]
51 | }];
52 | }
53 | }
54 |
55 | enum abstract EmptyPackageCode(String) to String {
56 | var MISSING_PACKAGE = "MissingPackage";
57 | var REDUNDANT_PACKAGE = "RedundantPackage";
58 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/design/InterfaceCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.design;
2 |
3 | /**
4 | Checks and enforces interface style. Either to allow properties and methods or just methods. Has an option to "allowMarkerInterfaces".
5 | **/
6 | @name("Interface")
7 | @desc("Checks and enforces interface style. Either to allow properties and methods or just methods. Has an option to `allowMarkerInterfaces`.")
8 | class InterfaceCheck extends Check {
9 | /**
10 | allows empty marker interfaces, or forbid their use
11 | **/
12 | public var allowMarkerInterfaces:Bool;
13 |
14 | /**
15 | allow properties inside interface types
16 | **/
17 | public var allowProperties:Bool;
18 |
19 | public function new() {
20 | super(TOKEN);
21 | allowMarkerInterfaces = true;
22 | allowProperties = false;
23 | categories = [Category.COMPLEXITY, Category.STYLE];
24 | points = 13;
25 | }
26 |
27 | override function actualRun() {
28 | var root:TokenTree = checker.getTokenTree();
29 | var interfaces:Array = root.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
30 | return switch (token.tok) {
31 | case Kwd(KwdInterface):
32 | FoundGoDeeper;
33 | default:
34 | GoDeeper;
35 | }
36 | });
37 | for (intr in interfaces) {
38 | var functions:Array = intr.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
39 | return switch (token.tok) {
40 | case Kwd(KwdFunction):
41 | FoundGoDeeper;
42 | default:
43 | GoDeeper;
44 | }
45 | });
46 | var vars:Array = intr.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
47 | return switch (token.tok) {
48 | case Kwd(KwdVar):
49 | FoundGoDeeper;
50 | default:
51 | GoDeeper;
52 | }
53 | });
54 |
55 | if (functions.length == 0 && vars.length == 0) {
56 | if (allowMarkerInterfaces) continue;
57 | else logPos("Marker interfaces are not allowed", intr.pos);
58 | }
59 |
60 | if (!allowProperties && vars.length > 0) logPos("Properties are not allowed in interfaces", intr.pos);
61 | }
62 | }
63 |
64 | override public function detectableInstances():DetectableInstances {
65 | return [{
66 | fixed: [],
67 | properties: [{
68 | propertyName: "allowMarkerInterfaces",
69 | values: [true, false]
70 | }, {
71 | propertyName: "allowProperties",
72 | values: [true, false]
73 | }]
74 | }];
75 | }
76 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/import.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks;
2 |
3 | import checkstyle.SeverityLevel;
--------------------------------------------------------------------------------
/src/checkstyle/checks/imports/AvoidStarImportCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.imports;
2 |
3 | /**
4 | Checks for import statements that use the * notation and using directives.
5 | **/
6 | @name("AvoidStarImport")
7 | @desc("Checks for import statements that use the * notation and using directives.")
8 | class AvoidStarImportCheck extends Check {
9 | public function new() {
10 | super(TOKEN);
11 | categories = [Category.STYLE, Category.CLARITY];
12 | points = 2;
13 | }
14 |
15 | override function actualRun() {
16 | var root:TokenTree = checker.getTokenTree();
17 | checkImports(root.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
18 | return switch (token.tok) {
19 | case Kwd(KwdImport):
20 | FoundSkipSubtree;
21 | case Kwd(_):
22 | SkipSubtree;
23 | default:
24 | GoDeeper;
25 | }
26 | }));
27 | }
28 |
29 | function checkImports(importEntries:Array) {
30 | for (entry in importEntries) {
31 | var stars:Array = entry.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
32 | return switch (token.tok) {
33 | case Binop(OpMult):
34 | FoundGoDeeper;
35 | default:
36 | GoDeeper;
37 | }
38 | });
39 |
40 | if (stars.length <= 0) continue;
41 | logPos('Using the ".*" form of import should be avoided', entry.getPos());
42 | }
43 | }
44 |
45 | override public function detectableInstances():DetectableInstances {
46 | return [{
47 | fixed: [],
48 | properties: [{
49 | propertyName: "severity",
50 | values: [SeverityLevel.INFO]
51 | }]
52 | }];
53 | }
54 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/literal/ArrayLiteralCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.literal;
2 |
3 | /**
4 | Checks if the array is instantiated using [] which is shorter and cleaner, not with new.
5 | **/
6 | @name("ArrayLiteral", "ArrayInstantiation")
7 | @desc("Checks if the array is instantiated using [] which is shorter and cleaner, not with new.")
8 | class ArrayLiteralCheck extends Check {
9 | public function new() {
10 | super(AST);
11 | categories = [Category.STYLE, Category.CLARITY];
12 | }
13 |
14 | override function actualRun() {
15 | if (checker.ast == null) return;
16 | checker.ast.walkFile(function(e:Expr) {
17 | switch (e.expr) {
18 | case ENew({pack: [], name: "Array"}, _):
19 | logPos('Bad array instantiation, use the array literal notation "[]" which is shorter and cleaner', e.pos);
20 | default:
21 | }
22 | });
23 | }
24 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/literal/ERegLiteralCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.literal;
2 |
3 | /**
4 | Checks for usage of EReg literals (between ~/ and /) instead of new.
5 | **/
6 | @name("ERegLiteral", "ERegInstantiation")
7 | @desc("Checks for usage of EReg literals (between ~/ and /) instead of new.")
8 | class ERegLiteralCheck extends Check {
9 | public function new() {
10 | super(AST);
11 | categories = [Category.STYLE, Category.CLARITY];
12 | }
13 |
14 | override function actualRun() {
15 | if (checker.ast == null) return;
16 | checker.ast.walkFile(function(e:Expr) {
17 | if (isPosSuppressed(e.pos)) return;
18 | switch (e.expr) {
19 | case ENew({pack: [], name: "EReg"}, [{expr: EConst(CString(re)), pos: _}, {expr: EConst(CString(opt)), pos: _}]):
20 | if (~/\$\{.+\}/.match(re)) return;
21 | logPos('Bad EReg instantiation, define expression between "~/" and "/"', e.pos);
22 | default:
23 | }
24 | });
25 | }
26 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/literal/HexadecimalLiteralCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.literal;
2 |
3 | /**
4 | Checks the letter case of hexadecimal literals.
5 | **/
6 | @name("HexadecimalLiteral", "HexadecimalLiterals")
7 | @desc("Checks the letter case of hexadecimal literals.")
8 | class HexadecimalLiteralCheck extends Check {
9 | /**
10 | policy for hexadecimal literals
11 | - upperCase = use uppercase for all letters
12 | - lowerCase = use lowercase for all letters
13 | **/
14 | public var option:HexadecimalLiteralPolicy;
15 |
16 | public function new() {
17 | super(AST);
18 | option = UPPER_CASE;
19 | categories = [Category.STYLE, Category.CLARITY];
20 | points = 1;
21 | }
22 |
23 | override function actualRun() {
24 | if (checker.ast == null) return;
25 | checker.ast.walkFile(function(e:Expr) {
26 | switch (e.expr) {
27 | case EConst(CInt(s)):
28 | checkString(s, e.pos);
29 | default:
30 | }
31 | });
32 | }
33 |
34 | function checkString(s:String, p) {
35 | var prefix = s.substr(0, 2);
36 | if (prefix.toLowerCase() == "0x") {
37 | var bodyActual = s.substr(2);
38 | var bodyExpected = bodyActual;
39 | if (option == LOWER_CASE) bodyExpected = bodyExpected.toLowerCase();
40 | else bodyExpected = bodyExpected.toUpperCase();
41 | if (bodyExpected != bodyActual) logPos("Bad hexadecimal literal, use " + option, p);
42 | }
43 | }
44 | }
45 |
46 | /**
47 | policy for hexadecimal literals
48 | - upperCase = use uppercase for all letters
49 | - lowerCase = use lowercase for all letters
50 | **/
51 | enum abstract HexadecimalLiteralPolicy(String) {
52 | var UPPER_CASE = "upperCase";
53 | var LOWER_CASE = "lowerCase";
54 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/meta/RedundantAccessMetaCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.meta;
2 |
3 | /**
4 | Checks for redundant @:access metadata
5 | **/
6 | @name("RedundantAccessMeta")
7 | @desc("Checks for redundant @:access metadata")
8 | class RedundantAccessMetaCheck extends RedundantAccessMetaBase {
9 | public function new() {
10 | super("access");
11 | }
12 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/meta/RedundantAccessMetaInfo.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.meta;
2 |
3 | typedef RedundantAccessMetaInfo = {
4 | var name:String;
5 | var ident:String;
6 | var token:TokenTree;
7 | var pos:Position;
8 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/meta/RedundantAllowMetaCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.meta;
2 |
3 | /**
4 | Checks for redundant @:allow metadata
5 | **/
6 | @name("RedundantAllowMeta")
7 | @desc("Checks for redundant @:allow metadata")
8 | class RedundantAllowMetaCheck extends RedundantAccessMetaBase {
9 | public function new() {
10 | super("allow");
11 | }
12 |
13 | override function filerParent(parent:TokenTree, info:RedundantAccessMetaInfo):Bool {
14 | var access:TokenTreeAccessHelper = TokenTreeAccessHelper.access(parent).firstOf(Kwd(KwdPublic));
15 | if (access.token == null) {
16 | return false;
17 | }
18 | logPos('Redundant "@:allow(${info.name})" for public field "${info.ident}" detected', info.token.getPos());
19 | return true;
20 | }
21 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/modifier/FinalCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.modifier;
2 |
3 | #if (haxe4)
4 | /**
5 | Checks for places that use var instead of final (Haxe 4+).
6 | **/
7 | @name("Final", "InlineFinal")
8 | @desc("Checks for places that use var instead of final (Haxe 4+).")
9 | class FinalCheck extends Check {
10 | public function new() {
11 | super(AST);
12 | categories = [Category.STYLE, Category.CLARITY];
13 | points = 1;
14 | }
15 |
16 | override function actualRun() {
17 | forEachField(checkField);
18 | }
19 |
20 | function checkField(f:Field, p:ParentType) {
21 | switch (f.kind) {
22 | case FVar(_):
23 | case FFun(_):
24 | return;
25 | case FProp(_):
26 | return;
27 | }
28 | if (f.access.contains(AFinal)) return;
29 |
30 | if (checkInlineVar(f)) {
31 | logPos('Consider using "inline final" for field "${f.name}"', f.pos, USE_INLINE_FINAL);
32 | return;
33 | }
34 | if (checkPublicStatic(f)) {
35 | logPos('Consider making public static field "${f.name}" "final" or "private"', f.pos, SHOULD_BE_PUBLIC_FINAL);
36 | return;
37 | }
38 | }
39 |
40 | function checkPublicStatic(f:Field):Bool {
41 | return (f.access.contains(APublic)) && (f.access.contains(AStatic));
42 | }
43 |
44 | function checkInlineVar(f:Field):Bool {
45 | return (f.access.contains(AInline));
46 | }
47 |
48 | override public function detectableInstances():DetectableInstances {
49 | return [{
50 | fixed: [],
51 | properties: [{
52 | propertyName: "severity",
53 | values: [SeverityLevel.INFO]
54 | }]
55 | }];
56 | }
57 | }
58 |
59 | enum abstract FinalCode(String) to String {
60 | var USE_INLINE_FINAL = "UseInlineFinal";
61 | var SHOULD_BE_PUBLIC_FINAL = "ShouldBePublicFinal";
62 | }
63 | #end
--------------------------------------------------------------------------------
/src/checkstyle/checks/modifier/PublicAccessorCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.modifier;
2 |
3 | /**
4 | Checks for public accessors.
5 | **/
6 | @name("PublicAccessor")
7 | @desc("Checks for public accessors.")
8 | class PublicAccessorCheck extends Check {
9 | public function new() {
10 | super(AST);
11 | categories = [Category.STYLE, Category.CLARITY];
12 | points = 1;
13 | }
14 |
15 | override function actualRun() {
16 | forEachField(checkField);
17 | }
18 |
19 | function checkField(f:Field, p:ParentType) {
20 | if (!f.kind.match(FFun(_))) return;
21 | if (!f.name.startsWith("set_") && !f.name.startsWith("get_")) return;
22 |
23 | var isDefaultPrivate = f.isDefaultPrivate(p);
24 | if (isDefaultPrivate && !f.access.contains(APublic)) return;
25 | else if (!isDefaultPrivate && f.access.contains(APrivate)) return;
26 |
27 | logPos("Accessor method should not be public", f.pos);
28 | }
29 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/naming/CatchParameterNameCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.naming;
2 |
3 | /**
4 | Checks that catch parameter names conform to a format specified by the "format" property.
5 | **/
6 | @name("CatchParameterName")
7 | @desc("Checks that catch parameter names conform to a format specified by the `format` property.")
8 | class CatchParameterNameCheck extends Check {
9 | /**
10 | regex name format
11 | **/
12 | public var format:String;
13 |
14 | public function new() {
15 | super(TOKEN);
16 | format = "^(e|t|ex|[a-z][a-z][a-zA-Z]+)$";
17 | }
18 |
19 | override function actualRun() {
20 | var formatRE = new EReg(format, "");
21 | var root:TokenTree = checker.getTokenTree();
22 | var catchTokens = root.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
23 | return switch (token.tok) {
24 | case Kwd(KwdCatch):
25 | FoundGoDeeper;
26 | default:
27 | GoDeeper;
28 | }
29 | });
30 |
31 | for (tkn in catchTokens) {
32 | for (item in tkn.children) {
33 | var child:TokenTree = item.getFirstChild();
34 | if (child == null) continue;
35 | switch (child.tok) {
36 | case Const(CIdent(name)):
37 | if (item.matches(POpen)) {
38 | if (!formatRE.match(name)) logPos('"$name" must match pattern "~/${format}/"', item.pos);
39 | continue;
40 | }
41 | default:
42 | }
43 | }
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/naming/FileNameCaseCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.naming;
2 |
3 | import haxe.io.Path;
4 |
5 | /**
6 | Checks that file names match the case of their module name.
7 | **/
8 | @name("FileNameCase")
9 | @desc("Checks that file names match the case of their module name.")
10 | class FileNameCaseCheck extends Check {
11 | public function new() {
12 | super(TOKEN);
13 | }
14 |
15 | override function actualRun() {
16 | var fileName:String = Path.withoutDirectory(checker.file.name);
17 | fileName = Path.withoutExtension(fileName);
18 | checkFile(fileName, checker);
19 | }
20 |
21 | function checkFile(fileName:String, checker:Checker) {
22 | var types:Array = getTypes(checker.getTokenTree());
23 | var lowerFileName:String = fileName.toLowerCase();
24 | if (fileName == "import") {
25 | if (types.length <= 0) {
26 | return;
27 | }
28 | log('"import.hx" contains types', 0, 0, 0, 0);
29 | return;
30 | }
31 | if ((lowerFileName == "import") && (types.length == 0)) {
32 | // ImPort.hx with types
33 | log('"$fileName.hx" contains no types - consider renaming to "import.hx"', 0, 0, 0, 0);
34 | return;
35 | }
36 | if (!types.contains(fileName)) {
37 | for (type in types) {
38 | var lowerType:String = type.toLowerCase();
39 | if (lowerType == lowerFileName) {
40 | log('"$fileName.hx" defines type "$type" using different case', 0, 0, 0, 0);
41 | }
42 | }
43 | log('"$fileName.hx" defines no type with name "$fileName"', 0, 0, 0, 0);
44 | return;
45 | }
46 | }
47 |
48 | function getTypes(token:TokenTree):Array {
49 | var types:Array = checker.getTokenTree().filterCallback(function(token:TokenTree, depth:Int):FilterResult {
50 | return switch (token.tok) {
51 | case Kwd(KwdAbstract) | Kwd(KwdClass) | Kwd(KwdEnum) | Kwd(KwdInterface) | Kwd(KwdTypedef):
52 | FoundSkipSubtree;
53 | default:
54 | GoDeeper;
55 | }
56 | });
57 | var typeNames:Array = [];
58 | for (type in types) {
59 | switch (type.tok) {
60 | case Kwd(KwdAbstract) | Kwd(KwdClass) | Kwd(KwdEnum) | Kwd(KwdInterface) | Kwd(KwdTypedef):
61 | var child:Null = type.getFirstChild();
62 | if (child == null) {
63 | continue;
64 | }
65 | switch (child.tok) {
66 | case Const(CIdent(s)):
67 | typeNames.push(s);
68 | default:
69 | }
70 | default:
71 | }
72 | }
73 |
74 | return typeNames;
75 | }
76 |
77 | override public function detectableInstances():DetectableInstances {
78 | return [{
79 | fixed: [],
80 | properties: [{
81 | propertyName: "severity",
82 | values: [SeverityLevel.WARNING]
83 | }]
84 | }];
85 | }
86 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/naming/ListenerNameCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.naming;
2 |
3 | /**
4 | Checks the naming conventions of event listener functions specified using "listeners" property.
5 | **/
6 | @name("ListenerName")
7 | @desc("Checks the naming conventions of event listener functions specified using `listeners` property.")
8 | class ListenerNameCheck extends Check {
9 | /**
10 | list of function names used to register listeners
11 | **/
12 | public var listeners:Array;
13 |
14 | /**
15 | regex name format
16 | **/
17 | public var format:String;
18 |
19 | var formatRE:EReg;
20 |
21 | public function new() {
22 | super(AST);
23 | listeners = ["addEventListener", "addListener", "on", "once"];
24 | format = "^_?[a-z][a-zA-Z0-9]*$";
25 | }
26 |
27 | override public function actualRun() {
28 | checker.ast.walkFile(function(e) {
29 | if (isPosSuppressed(e.pos)) return;
30 | switch (e.expr) {
31 | case ECall(e, params):
32 | searchCall(e, params);
33 | default:
34 | }
35 | });
36 | }
37 |
38 | function searchCall(e, p) {
39 | for (listener in listeners) if (searchLeftCall(e, listener)) searchCallParam(p);
40 | }
41 |
42 | function searchLeftCall(e, name):Bool {
43 | switch (e.expr) {
44 | case EConst(CIdent(ident)):
45 | return ident == name;
46 | case EField(e2, field):
47 | return field == name;
48 | default:
49 | return false;
50 | }
51 | }
52 |
53 | function searchCallParam(p:Array) {
54 | if (p.length < 2) return;
55 | var listener = p[1];
56 | switch (listener.expr) {
57 | case EConst(CIdent(ident)):
58 | checkListenerName(ident, listener.pos);
59 | default:
60 | }
61 | }
62 |
63 | function checkListenerName(name:String, pos:Position) {
64 | formatRE = new EReg(format, "");
65 | var match = formatRE.match(name);
66 | if (!match) logPos('Wrong listener name: "${name}" (should be "~/${format}/")', pos);
67 | }
68 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/naming/LocalVariableNameCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.naming;
2 |
3 | /**
4 | Checks that the local variable names conform to a format specified by the "format" property.
5 | **/
6 | @name("LocalVariableName")
7 | @desc("Checks that the local variable names conform to a format specified by the `format` property.")
8 | class LocalVariableNameCheck extends NameCheckBase {
9 | public function new() {
10 | super();
11 | format = "^[a-z][a-zA-Z0-9]*$";
12 | }
13 |
14 | override function actualRun() {
15 | formatRE = new EReg(format, "");
16 | if (checker.ast == null) return;
17 | checker.ast.walkFile(function(e) {
18 | switch (e.expr) {
19 | case EVars(vars):
20 | if (ignoreExtern && isPosExtern(e.pos)) return;
21 | if (isPosSuppressed(e.pos)) return;
22 | for (v in vars) {
23 | matchTypeName("local var", v.name, e.pos);
24 | }
25 | default:
26 | }
27 | });
28 | }
29 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/naming/MethodNameCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.naming;
2 |
3 | /**
4 | Checks that method names conform to a format specified by the "format" property.
5 | **/
6 | @name("MethodName")
7 | @desc("Checks that method names conform to a format specified by the `format` property.")
8 | class MethodNameCheck extends NameCheckBase {
9 | public function new() {
10 | super();
11 | format = "^[a-z][a-zA-Z0-9]*$";
12 | }
13 |
14 | override function checkClassType(decl:TypeDef, d:Definition>, pos:Position) {
15 | if (ignoreExtern && d.flags.contains(HExtern)) return;
16 | if (d.flags.contains(HInterface)) return;
17 | checkFields(d.data, decl.toParentType());
18 | }
19 |
20 | override function checkAbstractType(decl:TypeDef, d:Definition>, pos:Position) {
21 | checkFields(d.data, decl.toParentType());
22 | }
23 |
24 | override function checkTypedefType(decl:TypeDef, d:Definition, pos:Position) {
25 | if (ignoreExtern && d.flags.contains(TDExtern)) return;
26 |
27 | var p = decl.toParentType();
28 | switch (d.data) {
29 | case TAnonymous(f):
30 | checkFields(f, p);
31 | default:
32 | }
33 | }
34 |
35 | function checkFields(d:Array, p:ParentType) {
36 | for (field in d) {
37 | if (isCheckSuppressed(field)) continue;
38 | switch (field.kind) {
39 | case FFun(f):
40 | checkField(field, p);
41 | default:
42 | }
43 | }
44 | }
45 |
46 | function checkField(f:Field, p:ParentType) {
47 | if (f.isGetter() || f.isSetter()) return;
48 | if (hasToken(NOTINLINE) && !hasToken(INLINE) && f.isInline(p)) return;
49 | if (hasToken(INLINE) && !hasToken(NOTINLINE) && !f.isInline(p)) return;
50 | if (hasToken(NOTSTATIC) && !hasToken(STATIC) && f.isStatic(p)) return;
51 | if (hasToken(STATIC) && !hasToken(NOTSTATIC) && !f.isStatic(p)) return;
52 | if (hasToken(PUBLIC) && !hasToken(PRIVATE) && !f.isPublic(p)) return;
53 | if (hasToken(PRIVATE) && !hasToken(PUBLIC) && !f.isPrivate(p)) return;
54 |
55 | matchTypeName("method name", f.name, f.pos);
56 | }
57 | }
58 |
59 | /**
60 | check applies to:
61 | - PUBLIC = all public methods
62 | - PRIVATE = all private methods
63 | - STATIC = all static methods
64 | - NOTSTATIC = all non static methods
65 | - INLINE = all inline methods
66 | - NOTINLINE = all non-inline methods
67 | **/
68 | enum abstract MethodNameCheckToken(String) {
69 | var PUBLIC = "PUBLIC";
70 | var PRIVATE = "PRIVATE";
71 | var STATIC = "STATIC";
72 | var NOTSTATIC = "NOTSTATIC";
73 | var INLINE = "INLINE";
74 | var NOTINLINE = "NOTINLINE";
75 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/naming/NameCheckBase.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.naming;
2 |
3 | /**
4 | Base class for name checks
5 | **/
6 | @ignore("Base class for name checks")
7 | class NameCheckBase extends Check {
8 | /**
9 | regex name format
10 | **/
11 | public var format:String;
12 |
13 | /**
14 | list of tokens to limit where names should conform to "format"
15 | **/
16 | public var tokens:Array;
17 |
18 | /**
19 | ignores names inside extern types
20 | **/
21 | public var ignoreExtern:Bool;
22 |
23 | var formatRE:EReg;
24 |
25 | public function new() {
26 | super(AST);
27 | format = "^.*$";
28 | tokens = [];
29 | ignoreExtern = true;
30 | categories = [Category.STYLE, Category.CLARITY];
31 | }
32 |
33 | function hasToken(token:T):Bool {
34 | return (tokens.length == 0 || tokens.contains(token));
35 | }
36 |
37 | override function actualRun() {
38 | formatRE = new EReg(format, "");
39 | checkClassFields();
40 | }
41 |
42 | function checkClassFields() {
43 | if (checker.ast == null) return;
44 | for (td in checker.ast.decls) {
45 | switch (td.decl) {
46 | case EClass(d):
47 | checkClassType(td.decl, d, td.pos);
48 | case EEnum(d):
49 | checkEnumType(td.decl, d, td.pos);
50 | case EAbstract(d):
51 | checkAbstractType(td.decl, d, td.pos);
52 | case ETypedef(d):
53 | checkTypedefType(td.decl, d, td.pos);
54 | default:
55 | }
56 | }
57 | }
58 |
59 | function checkClassType(decl:TypeDef, d:Definition>, pos:Position) {}
60 |
61 | function checkEnumType(decl:TypeDef, d:Definition>, pos:Position) {}
62 |
63 | function checkAbstractType(decl:TypeDef, d:Definition>, pos:Position) {}
64 |
65 | function checkTypedefType(decl:TypeDef, d:Definition, pos:Position) {}
66 |
67 | function matchTypeName(type:String, name:String, pos:Position) {
68 | if (!formatRE.match(name)) {
69 | warn(type, name, pos);
70 | }
71 | }
72 |
73 | function warn(type:String, name:String, pos:Position) {
74 | logPos('Invalid ${type} signature: "${name}" (name should be "~/${format}/")', pos);
75 | }
76 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/naming/ParameterNameCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.naming;
2 |
3 | /**
4 | Checks that parameter names conform to a format specified by the "format" property.
5 | **/
6 | @name("ParameterName")
7 | @desc("Checks that parameter names conform to a format specified by the `format` property.")
8 | class ParameterNameCheck extends NameCheckBase {
9 | public function new() {
10 | super();
11 | format = "^(_|[a-z][a-zA-Z0-9]*$)";
12 | }
13 |
14 | override function checkClassType(decl:TypeDef, d:Definition>, pos:Position) {
15 | if (ignoreExtern && d.flags.contains(HExtern)) return;
16 | checkFields(d.data);
17 | }
18 |
19 | override function checkEnumType(decl:TypeDef, d:Definition>, pos:Position) {
20 | if (ignoreExtern && d.flags.contains(EExtern)) return;
21 | checkEnumFields(d.data);
22 | }
23 |
24 | override function checkAbstractType(decl:TypeDef, d:Definition>, pos:Position) {
25 | checkFields(d.data);
26 | }
27 |
28 | override function checkTypedefType(decl:TypeDef, d:Definition, pos:Position) {
29 | if (ignoreExtern && d.flags.contains(TDExtern)) return;
30 | switch (d.data) {
31 | case TAnonymous(f):
32 | checkFields(f);
33 | default:
34 | }
35 | }
36 |
37 | function checkFields(d:Array) {
38 | for (field in d) {
39 | if (isCheckSuppressed(field)) continue;
40 | switch (field.kind) {
41 | case FFun(f):
42 | checkField(f.args, field.pos);
43 | default:
44 | }
45 | }
46 | }
47 |
48 | function checkEnumFields(d:Array) {
49 | for (field in d) {
50 | for (arg in field.args) matchTypeName("parameter name", arg.name, field.pos);
51 | }
52 | }
53 |
54 | function checkField(args:Array, pos:Position) {
55 | if (args == null || args.length <= 0) return;
56 | for (arg in args) matchTypeName("parameter name", arg.name, pos);
57 | }
58 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/naming/TypeNameCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.naming;
2 |
3 | /**
4 | Checks that type names conform to a format specified by the "format" property.
5 | **/
6 | @name("TypeName")
7 | @desc("Checks that type names conform to a format specified by the `format` property.")
8 | class TypeNameCheck extends NameCheckBase {
9 | public function new() {
10 | super();
11 | format = "^[A-Z]+[a-zA-Z0-9]*$";
12 | }
13 |
14 | override function checkClassType(decl:TypeDef, d:Definition>, pos:Position) {
15 | if (ignoreExtern && d.flags.contains(HExtern)) return;
16 |
17 | var isInterface:Bool = (d.flags.contains(HInterface));
18 |
19 | if (!hasToken(INTERFACE) && isInterface) return;
20 | if (!hasToken(CLASS) && !isInterface) return;
21 | if (isInterface) {
22 | matchTypeName("interface", d.name, pos);
23 | }
24 | else {
25 | matchTypeName("class", d.name, pos);
26 | }
27 | }
28 |
29 | override function checkEnumType(decl:TypeDef, d:Definition>, pos:Position) {
30 | if (!hasToken(ENUM)) return;
31 | if (ignoreExtern && d.flags.contains(EExtern)) return;
32 |
33 | matchTypeName("enum", d.name, pos);
34 | }
35 |
36 | override function checkAbstractType(decl:TypeDef, d:Definition>, pos:Position) {
37 | if (!hasToken(ABSTRACT)) return;
38 | matchTypeName("abstract", d.name, pos);
39 | }
40 |
41 | override function checkTypedefType(decl:TypeDef, d:Definition, pos:Position) {
42 | if (!hasToken(TYPEDEF)) return;
43 | if (ignoreExtern && d.flags.contains(TDExtern)) return;
44 |
45 | matchTypeName("typedef", d.name, pos);
46 | }
47 | }
48 |
49 | /**
50 | check applies to:
51 | - INTERFACE = all interface types
52 | - CLASS = all class types
53 | - ENUM = all enum types
54 | - ABSTRACT = all abstract types
55 | - TYPEDEF = all typedef types
56 | **/
57 | enum abstract TypeNameCheckToken(String) {
58 | var INTERFACE = "INTERFACE";
59 | var CLASS = "CLASS";
60 | var ENUM = "ENUM";
61 | var ABSTRACT = "ABSTRACT";
62 | var TYPEDEF = "TYPEDEF";
63 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/size/FileLengthCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.size;
2 |
3 | import checkstyle.checks.whitespace.ListOfEmptyLines;
4 |
5 | /**
6 | Checks for long source files. If a source file becomes very long it is hard to understand.
7 | Therefore long classes should usually be refactored into several individual classes that focus on a specific task.
8 | **/
9 | @name("FileLength")
10 | @desc("Checks for long source files. If a source file becomes very long it is hard to understand. Therefore long classes should usually be refactored into several individual classes that focus on a specific task.")
11 | class FileLengthCheck extends Check {
12 | static var DEFAULT_MAX_LENGTH:Int = 1000;
13 |
14 | /**
15 | maximum number of lines permitted per file (default: 2000)
16 | **/
17 | public var max:Int;
18 |
19 | /**
20 | ignores or includes empty lines when counting total file length
21 | **/
22 | public var ignoreEmptyLines:Bool;
23 |
24 | public function new() {
25 | super(LINE);
26 | max = DEFAULT_MAX_LENGTH;
27 | ignoreEmptyLines = true;
28 | categories = [Category.COMPLEXITY, Category.CLARITY];
29 | points = 21;
30 | }
31 |
32 | override function actualRun() {
33 | if (checker.ast == null) return;
34 |
35 | for (td in checker.ast.decls) {
36 | switch (td.decl) {
37 | case EClass(d):
38 | for (field in d.data) if (isCheckSuppressed(field)) return;
39 | default:
40 | }
41 | }
42 |
43 | var count = checker.lines.length;
44 | if (ignoreEmptyLines) {
45 | var emptyLines:ListOfEmptyLines = ListOfEmptyLines.detectEmptyLines(checker);
46 | count -= emptyLines.lines.length;
47 | }
48 | if (count > max) {
49 | log('File length is ${checker.lines.length} lines (max allowed is ${max})', checker.lines.length, 0, checker.lines.length, 0);
50 | }
51 | }
52 |
53 | override public function detectableInstances():DetectableInstances {
54 | return [{
55 | fixed: [],
56 | properties: [{
57 | propertyName: "max",
58 | values: [for (i in 0...10) 400 + i * 100]
59 | }]
60 | }];
61 | }
62 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/size/LineLengthCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.size;
2 |
3 | /**
4 | Checks for long lines. Long lines are hard to read.
5 | **/
6 | @name("LineLength")
7 | @desc("Checks for long lines. Long lines are hard to read.")
8 | class LineLengthCheck extends Check {
9 | static var DEFAULT_MAX_LENGTH:Int = 160;
10 |
11 | /**
12 | maximum number of characters per line (default: 160)
13 | **/
14 | public var max:Int;
15 |
16 | /**
17 | ignore lines matching regex
18 | **/
19 | public var ignorePattern:String;
20 |
21 | public function new() {
22 | super(LINE);
23 | max = DEFAULT_MAX_LENGTH;
24 | ignorePattern = "^$";
25 | categories = [Category.COMPLEXITY, Category.CLARITY];
26 | points = 2;
27 | }
28 |
29 | override function actualRun() {
30 | var ignoreRE = new EReg(ignorePattern, "");
31 | for (i in 0...checker.lines.length) {
32 | var line = checker.lines[i];
33 | if (line.length > max) {
34 | if (ignoreRE.match(line) || isLineSuppressed(i)) continue;
35 | log('Line is longer than ${max} characters (found ${line.length})', i + 1, 0, i + 1, line.length);
36 | }
37 | }
38 | }
39 |
40 | override public function detectableInstances():DetectableInstances {
41 | return [{
42 | fixed: [],
43 | properties: [{
44 | propertyName: "max",
45 | values: [for (i in 0...7) 80 + i * 20]
46 | }]
47 | }];
48 | }
49 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/size/ParameterNumberCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.size;
2 |
3 | import checkstyle.utils.PosHelper;
4 |
5 | /**
6 | Checks the number of parameters of a method.
7 | **/
8 | @name("ParameterNumber")
9 | @desc("Checks the number of parameters of a method.")
10 | class ParameterNumberCheck extends Check {
11 | static var DEFAULT_MAX_PARAMS:Int = 7;
12 |
13 | /**
14 | maximum number of parameters per method (default: 7)
15 | **/
16 | public var max:Int;
17 |
18 | /**
19 | ignore methods with "override", only base class violates
20 | **/
21 | public var ignoreOverriddenMethods:Bool;
22 |
23 | public function new() {
24 | super(AST);
25 | max = DEFAULT_MAX_PARAMS;
26 | ignoreOverriddenMethods = false;
27 | categories = [Category.COMPLEXITY, Category.CLARITY];
28 | points = 5;
29 | }
30 |
31 | override function actualRun() {
32 | forEachField(checkField);
33 | }
34 |
35 | function checkField(f:Field, _) {
36 | if (ignoreOverriddenMethods && f.access.contains(AOverride)) return;
37 | switch (f.kind) {
38 | case FFun(fun):
39 | if ((fun.args != null) && (fun.args.length > max)) {
40 | warnMaxParameter(f.name, PosHelper.makeFieldSignaturePosition(f));
41 | }
42 | default:
43 | }
44 | }
45 |
46 | function warnMaxParameter(name:String, pos:Position) {
47 | logPos('Too many parameters for function: ${name} (> ${max})', pos);
48 | }
49 |
50 | override public function detectableInstances():DetectableInstances {
51 | return [{
52 | fixed: [],
53 | properties: [{
54 | propertyName: "max",
55 | values: [for (i in 4...15) i]
56 | }, {
57 | propertyName: "ignoreOverriddenMethods",
58 | values: [true, false]
59 | }]
60 | }];
61 | }
62 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/type/AnonymousCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.type;
2 |
3 | /**
4 | Check to find any anonymous type structures used.
5 | **/
6 | @name("Anonymous")
7 | @desc("Check to find any anonymous type structures used.")
8 | class AnonymousCheck extends Check {
9 | public function new() {
10 | super(AST);
11 | categories = [Category.STYLE, Category.CLARITY, Category.BUG_RISK, Category.COMPLEXITY];
12 | points = 8;
13 | }
14 |
15 | override function actualRun() {
16 | forEachField(checkField);
17 | checkLocalVars();
18 | }
19 |
20 | function checkField(f:Field, _) {
21 | if (f.isConstructor()) return;
22 | switch (f.kind) {
23 | case FVar(TAnonymous(fields), val):
24 | error(f.name, f.pos);
25 | default:
26 | }
27 | }
28 |
29 | function checkLocalVars() {
30 | if (checker.ast == null) return;
31 | checker.ast.walkFile(function(e) {
32 | switch (e.expr) {
33 | case EVars(vars):
34 | for (v in vars) {
35 | if (v.type == null) continue;
36 | switch (v.type) {
37 | case TAnonymous(fields): error(v.name, e.pos);
38 | default:
39 | }
40 | }
41 | default:
42 | }
43 | });
44 | }
45 |
46 | function error(name:String, pos:Position) {
47 | logPos('Anonymous structure "${name}" found, use "typedef"', pos);
48 | }
49 |
50 | override public function detectableInstances():DetectableInstances {
51 | return [{
52 | fixed: [],
53 | properties: [{
54 | propertyName: "severity",
55 | values: [SeverityLevel.INFO]
56 | }]
57 | }];
58 | }
59 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/type/AvoidIdentifierCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.type;
2 |
3 | /**
4 | Checks for identifiers to avoid.
5 | **/
6 | @name("AvoidIdentifier")
7 | @desc("Checks for identifiers to avoid.")
8 | class AvoidIdentifierCheck extends Check {
9 | /**
10 | list of identifiers to avoid
11 | **/
12 | public var avoidIdentifiers:Array;
13 |
14 | public function new() {
15 | super(TOKEN);
16 | avoidIdentifiers = [];
17 | }
18 |
19 | override function actualRun() {
20 | var root:TokenTree = checker.getTokenTree();
21 | root.filterCallback(function(token:TokenTree, index:Int):FilterResult {
22 | switch (token.tok) {
23 | case Const(CIdent(ident)):
24 | checkIdent(ident, token);
25 | default:
26 | }
27 | return GoDeeper;
28 | });
29 | }
30 |
31 | function checkIdent(ident:String, token:TokenTree) {
32 | if (isPosSuppressed(token.pos)) return;
33 | if (avoidIdentifiers.indexOf(ident) < 0) return;
34 | error(ident, token.pos);
35 | }
36 |
37 | function error(name:String, pos:Position) {
38 | logPos('Identifier "${name}" should be avoided', pos);
39 | }
40 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/type/DynamicCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.type;
2 |
3 | /**
4 | Checks for use of Dynamic type anywhere in the code.
5 | **/
6 | @name("Dynamic")
7 | @desc("Checks for use of Dynamic type anywhere in the code.")
8 | class DynamicCheck extends Check {
9 | public function new() {
10 | super(TOKEN);
11 | categories = [Category.CLARITY, Category.BUG_RISK, Category.COMPLEXITY];
12 | points = 3;
13 | }
14 |
15 | override function actualRun() {
16 | var root:TokenTree = checker.getTokenTree();
17 | root.filterCallback(function(token:TokenTree, index:Int):FilterResult {
18 | switch token.tok {
19 | case Const(CIdent("Dynamic")):
20 | if (isPosSuppressed(token.pos)) return SkipSubtree;
21 | logPos('Avoid using "Dynamic" as type', token.pos);
22 | return SkipSubtree;
23 | default:
24 | return GoDeeper;
25 | }
26 | });
27 | }
28 |
29 | override public function detectableInstances():DetectableInstances {
30 | return [{
31 | fixed: [],
32 | properties: [{
33 | propertyName: "severity",
34 | values: [SeverityLevel.INFO]
35 | }]
36 | }];
37 | }
38 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/type/TypeCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.type;
2 |
3 | /**
4 | Checks if type is specified or not for member variables.
5 | **/
6 | @name("Type")
7 | @desc("Checks if type is specified or not for member variables.")
8 | class TypeCheck extends Check {
9 | /**
10 | ignores fields inside abstract enums
11 | **/
12 | public var ignoreEnumAbstractValues:Bool;
13 |
14 | public function new() {
15 | super(AST);
16 | ignoreEnumAbstractValues = true;
17 | categories = [Category.CLARITY];
18 | }
19 |
20 | override function actualRun() {
21 | forEachField(function(f, p) {
22 | if (f.isConstructor()) return;
23 | if (ignoreEnumAbstractValues && p.kind == ENUM_ABSTRACT && !f.access.contains(AStatic)) return;
24 | switch (f.kind) {
25 | case FVar(t, e):
26 | if (t == null) error(f.name, f.pos);
27 | case _:
28 | }
29 | });
30 | }
31 |
32 | function error(name:String, pos:Position) {
33 | logPos('Variable "${name}" type not specified', pos);
34 | }
35 |
36 | override public function detectableInstances():DetectableInstances {
37 | return [{
38 | fixed: [],
39 | properties: [{
40 | propertyName: "severity",
41 | values: [SeverityLevel.INFO]
42 | }]
43 | }];
44 | }
45 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/whitespace/ArrayAccessCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.whitespace;
2 |
3 | /**
4 | Checks for spaces before array access or inside array elements. Finds code like "a [0], a[ 0]", etc.
5 | **/
6 | @name("ArrayAccess")
7 | @desc("Checks for spaces before array access or inside array elements. Finds code like `a [0], a[ 0]`, etc.")
8 | class ArrayAccessCheck extends Check {
9 | /**
10 | set "spaceBefore" to false to detect space between array and "["
11 | **/
12 | public var spaceBefore:Bool;
13 |
14 | /**
15 | set to false to detect space between brackets ("[" + "]") and index
16 | **/
17 | public var spaceInside:Bool;
18 |
19 | public function new() {
20 | super(AST);
21 | spaceBefore = false;
22 | spaceInside = false;
23 | categories = [Category.STYLE, Category.CLARITY];
24 | }
25 |
26 | override function actualRun() {
27 | var lastExpr = null;
28 |
29 | if (checker.ast == null) return;
30 | checker.ast.walkFile(function(e:Expr) {
31 | if (lastExpr == null) {
32 | lastExpr = e;
33 | return;
34 | }
35 |
36 | switch (e.expr) {
37 | case EArray(e1, e2):
38 | if (!spaceBefore) {
39 | var e1length = e1.pos.max - e1.pos.min;
40 | var eString = checker.getString(e.pos.min, e.pos.max);
41 | if (eString.substr(e1length, 1) == " ") logPos("Space between array and [", e.pos);
42 | }
43 |
44 | if (!spaceInside) {
45 | if (checker.getString(e2.pos.min - 1, e2.pos.min) == " ") logPos("Space between [ and index", e.pos);
46 | if (checker.getString(e2.pos.max, e2.pos.max + 1) == " ") logPos("Space between index and ]", e.pos);
47 | }
48 | default:
49 | }
50 |
51 | lastExpr = e;
52 | });
53 | }
54 |
55 | override public function detectableInstances():DetectableInstances {
56 | return [{
57 | fixed: [],
58 | properties: [{
59 | propertyName: "spaceBefore",
60 | values: [true, false]
61 | }, {
62 | propertyName: "spaceInside",
63 | values: [true, false]
64 | }]
65 | }];
66 | }
67 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/whitespace/IndentationCharacterCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.whitespace;
2 |
3 | /**
4 | Checks indentation character (tab/space, default is tab).
5 | **/
6 | @name("IndentationCharacter")
7 | @desc("Checks indentation character (tab/space, default is tab).")
8 | class IndentationCharacterCheck extends LineCheckBase {
9 | /**
10 | set indentation to
11 | - tab = tab
12 | - space = space
13 | **/
14 | public var character:IndentationCharacterCheckCharacter;
15 |
16 | /**
17 | ignore lines that match regex
18 | **/
19 | public var ignorePattern:String;
20 |
21 | public function new() {
22 | super();
23 | severity = SeverityLevel.IGNORE;
24 | character = TAB;
25 | ignorePattern = "^$";
26 | }
27 |
28 | override function actualRun() {
29 | var ignoreRE = new EReg(ignorePattern, "");
30 | var re = (character == TAB) ? ~/^\t*(\S.*| \*.*)?$/ : ~/^ *(\S.*)?$/;
31 | for (i in 0...checker.lines.length) {
32 | var line = checker.lines[i];
33 | var ranges = getRanges(line);
34 | var startTextRange = ranges.filter(function(r):Bool return r.type == TEXT && r.start == 0)[0];
35 | if (startTextRange == null) continue;
36 | var startText = line.substring(startTextRange.start, startTextRange.end);
37 |
38 | if (ignoreRE.match(line) || isLineSuppressed(i)) continue;
39 | if (!re.match(startText)) log('Wrong indentation character (should be ${character})', i + 1, 0, i + 1, 0);
40 | }
41 | }
42 |
43 | override public function detectableInstances():DetectableInstances {
44 | return [{
45 | fixed: [],
46 | properties: [{
47 | propertyName: "character",
48 | values: [SPACE, TAB]
49 | }]
50 | }];
51 | }
52 | }
53 |
54 | /**
55 | indentation with
56 | - tab = tabs
57 | - space = space
58 | **/
59 | enum abstract IndentationCharacterCheckCharacter(String) {
60 | var TAB = "tab";
61 | var SPACE = "space";
62 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/whitespace/SeparatorWrapCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.whitespace;
2 |
3 | import checkstyle.checks.whitespace.WrapCheckBase.WrapCheckBaseOption;
4 |
5 | /**
6 | Checks line wrapping with separators.
7 | **/
8 | @name("SeparatorWrap")
9 | @desc("Checks line wrapping with separators.")
10 | class SeparatorWrapCheck extends WrapCheckBase {
11 | public function new() {
12 | super();
13 | tokens = [","];
14 | }
15 |
16 | override function actualRun() {
17 | var tokenList:Array = [];
18 |
19 | if (hasToken(",")) tokenList.push(Comma);
20 | if (hasToken(".")) tokenList.push(Dot);
21 |
22 | if (tokenList.length <= 0) return;
23 | checkTokens(tokenList);
24 | }
25 |
26 | override public function detectableInstances():DetectableInstances {
27 | return [{
28 | fixed: [],
29 | properties: [{
30 | propertyName: "option",
31 | values: [WrapCheckBaseOption.EOL, WrapCheckBaseOption.NL]
32 | }]
33 | }];
34 | }
35 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/whitespace/TabForAligningCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.whitespace;
2 |
3 | /**
4 | Checks if there are any tabs in the middle of a line.
5 | **/
6 | @name("TabForAligning")
7 | @desc("Checks if there are any tabs in the middle of a line.")
8 | class TabForAligningCheck extends LineCheckBase {
9 | /**
10 | ignore linex matching regex
11 | **/
12 | public var ignorePattern:String;
13 |
14 | public function new() {
15 | super();
16 | severity = SeverityLevel.IGNORE;
17 | ignorePattern = "^$";
18 | categories = [Category.STYLE, Category.CLARITY];
19 | }
20 |
21 | override function actualRun() {
22 | var ignoreRE = new EReg(ignorePattern, "");
23 | for (i in 0...checker.lines.length) {
24 | var line = checker.lines[i];
25 | var ranges = getRanges(line);
26 |
27 | if (ignoreRE.match(line)) continue;
28 |
29 | for (range in ranges.filter(function(r):Bool return r.type == TEXT)) {
30 | var re = range.start == 0 ? ~/\S[ ]*\t/ : ~/\t/;
31 | var rangeText = line.substring(range.start, range.end);
32 | if (re.match(rangeText)) log("Tab after non-space character, use space for aligning", i + 1, 0, i + 1, line.length);
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/whitespace/TrailingWhitespaceCheck.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.whitespace;
2 |
3 | /**
4 | Checks if there are any trailing white spaces.
5 | **/
6 | @name("TrailingWhitespace")
7 | @desc("Checks if there are any trailing white spaces.")
8 | class TrailingWhitespaceCheck extends LineCheckBase {
9 | public function new() {
10 | super();
11 | severity = SeverityLevel.IGNORE;
12 | }
13 |
14 | override function actualRun() {
15 | var re = ~/\s+$/;
16 | for (i in 0...checker.lines.length) {
17 | var line = checker.lines[i];
18 | var ranges = getRanges(line);
19 | var endTextRange = ranges.filter(function(r):Bool return r.type == TEXT && r.end == line.length)[0];
20 | if (endTextRange == null) continue;
21 | var endText = line.substring(endTextRange.start, endTextRange.end);
22 |
23 | if (re.match(endText)) log("Trailing whitespace", i + 1, line.length, i + 1, line.length);
24 | }
25 | }
26 |
27 | override public function detectableInstances():DetectableInstances {
28 | return [{
29 | fixed: [],
30 | properties: [{
31 | propertyName: "severity",
32 | values: ["INFO"]
33 | }]
34 | }];
35 | }
36 | }
--------------------------------------------------------------------------------
/src/checkstyle/checks/whitespace/WrapCheckBase.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.whitespace;
2 |
3 | import tokentree.utils.TokenTreeCheckUtils;
4 |
5 | /**
6 | base class for OperatorWrap and SeparatorWrap
7 | **/
8 | @ignore("base class for OperatorWrap and SeparatorWrap")
9 | class WrapCheckBase extends Check {
10 | /**
11 | list mof wrapping tokens
12 | **/
13 | public var tokens:Array;
14 |
15 | /**
16 | policy for wrapping token
17 | - eol = wrapping token should be at end of line
18 | - nl = wrapping token should start a new line
19 | **/
20 | public var option:WrapCheckBaseOption;
21 |
22 | public function new() {
23 | super(TOKEN);
24 | option = EOL;
25 | categories = [Category.STYLE, Category.CLARITY];
26 | }
27 |
28 | function hasToken(token:String):Bool {
29 | return (tokens.length == 0 || tokens.contains(token));
30 | }
31 |
32 | @:access(tokentree.TokenTree)
33 | function checkTokens(tokenList:Array) {
34 | var root:TokenTree = checker.getTokenTree();
35 | var allTokens:Array = root.filterCallback(function(token:TokenTree, depth:Int):FilterResult {
36 | if (token.matchesAny(tokenList)) {
37 | return FoundGoDeeper;
38 | }
39 | return GoDeeper;
40 | });
41 |
42 | for (tok in allTokens) {
43 | if (isPosSuppressed(tok.pos)) continue;
44 | if (TokenTreeCheckUtils.isOpGtTypedefExtension(tok)) continue;
45 | if (TokenTreeCheckUtils.isTypeParameter(tok)) continue;
46 | if (TokenTreeCheckUtils.isImportMult(tok)) continue;
47 | if (TokenTreeCheckUtils.filterOpSub(tok)) continue;
48 |
49 | var linePos:LinePos = checker.getLinePos(tok.pos.min);
50 | var line:Bytes = Bytes.ofString(checker.lines[linePos.line]);
51 | var before:String = line.sub(0, linePos.ofs).toString();
52 | var tokLen:Int = tok.toString().length;
53 | var offs:Int = linePos.ofs + tokLen;
54 | var after:String = line.sub(offs, line.length - offs).toString();
55 |
56 | if (~/^\s*$/.match(before)) {
57 | if (option != NL) {
58 | logPos('Token "$tok" must be at the end of the line', tok.pos);
59 | continue;
60 | }
61 | }
62 | if (~/^\s*(\/\/.*|\/\*.*|)$/.match(after)) {
63 | if (option != EOL) {
64 | logPos('Token "$tok" must be on a new line', tok.pos);
65 | }
66 | }
67 | }
68 | }
69 | }
70 |
71 | /**
72 | policy for wrapping token
73 | - eol = wrapping token should be at end of line
74 | - nl = wrapping token should start a new line
75 | **/
76 | enum abstract WrapCheckBaseOption(String) {
77 | var EOL = "eol";
78 | var NL = "nl";
79 | }
--------------------------------------------------------------------------------
/src/checkstyle/config/CheckConfig.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.config;
2 |
3 | typedef CheckConfig = {
4 | var type:String;
5 | @:optional var props:{};
6 | }
--------------------------------------------------------------------------------
/src/checkstyle/config/Config.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.config;
2 |
3 | import checkstyle.SeverityLevel;
4 |
5 | typedef Config = {
6 | /**
7 | Extend configuration from a master configuration file.
8 | Checks and excludes from both master and current configuration file form the final runtime configuration.
9 | There is no shadowing or overwriting checks or excludes, Checkstyle runs every check regardless where it comes from.
10 | A master configuration file can have its own "extendsConfigPath" entry. Checkstyle will walk up the chain as long as it does not cycle.
11 | **/
12 | @:optional var extendsConfigPath:String;
13 |
14 | /**
15 | Each check has a builtin severity level.
16 | Setting "defaultSeverity" applies its value to all checks that have no explicity "severity" field in their configuration
17 |
18 | @see checkstyle.SeverityLevel
19 | **/
20 | @:optional var defaultSeverity:SeverityLevel;
21 |
22 | /**
23 | defines that are always added
24 | **/
25 | @:optional var baseDefines:Array;
26 |
27 | /**
28 | different define combinations to use (on top of "baseDefines")
29 | **/
30 | @:optional var defineCombinations:Array>;
31 |
32 | /**
33 | Sets the number of checker threads, valid range is 1-15
34 | **/
35 | @:optional var numberOfCheckerThreads:Int;
36 |
37 | @:optional var checks:Array;
38 | @:optional var exclude:ExcludeConfig;
39 |
40 | /**
41 | version number
42 | **/
43 | @:optional var version:Int;
44 | }
--------------------------------------------------------------------------------
/src/checkstyle/config/ExcludeConfig.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.config;
2 |
3 | /**
4 | defines filters to exclude folders, types or files from all or specific checks
5 | **/
6 | typedef ExcludeConfig = {
7 | @:optional var path:ExcludePath;
8 |
9 | /**
10 | exclude matching files from all checks
11 | **/
12 | @:optional var all:ExcludeFilterList;
13 |
14 | /**
15 | version number
16 | **/
17 | @:optional var version:Int;
18 | }
19 |
20 | /**
21 | list of path filters, e.g.
22 | - full type names
23 | - names of individual folder or subfolders
24 | - partial folder or type names
25 |
26 | each line can have an additional range specification:
27 | - ":" = only matches a specific line number - valid line number start at 1
28 | - ":-" = matches line numbers from to (including both)
29 | - ":" = matches any line or block that has name (Haxe keywords currently unsupported)
30 | **/
31 | typedef ExcludeFilterList = Array;
--------------------------------------------------------------------------------
/src/checkstyle/config/ExcludeDefinition.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.config;
2 |
3 | enum ExcludeDefinition {
4 | FULL(filter:String);
5 | LINE(filter:String, line:Int);
6 | RANGE(filter:String, lineStart:Int, lineEnd:Int);
7 | IDENTIFIER(filter:String, name:String);
8 | }
--------------------------------------------------------------------------------
/src/checkstyle/config/ExcludePath.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.config;
2 |
3 | /**
4 | filters excludes relative to
5 | - RELATIVE_TO_PROJECT = use project root
6 | - RELATIVE_TO_SOURCE = use path(s) specified via "-s " command line switches
7 | **/
8 | enum abstract ExcludePath(String) {
9 | var RELATIVE_TO_PROJECT = "RELATIVE_TO_PROJECT";
10 | var RELATIVE_TO_SOURCE = "RELATIVE_TO_SOURCE";
11 | }
--------------------------------------------------------------------------------
/src/checkstyle/config/ExcludeRange.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.config;
2 |
3 | import checkstyle.Checker.LinePos;
4 |
5 | typedef ExcludeRange = {
6 | var checkName:String;
7 | var linePosStart:LinePos;
8 | var linePosEnd:LinePos;
9 | var charPosStart:Int;
10 | var charPosEnd:Int;
11 | }
--------------------------------------------------------------------------------
/src/checkstyle/detect/DetectableInstance.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.detect;
2 |
3 | typedef DetectableInstance = {
4 | var fixed:Array;
5 | var properties:DetectableProperties;
6 | }
--------------------------------------------------------------------------------
/src/checkstyle/detect/DetectableInstanceProperty.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.detect;
2 |
3 | typedef DetectableInstanceProperty = {
4 | var propertyName:String;
5 | var value:DetectableProperty;
6 | }
--------------------------------------------------------------------------------
/src/checkstyle/detect/DetectableInstances.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.detect;
2 |
3 | typedef DetectableInstances = Array;
--------------------------------------------------------------------------------
/src/checkstyle/detect/DetectableProperties.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.detect;
2 |
3 | typedef DetectableProperties = Array;
--------------------------------------------------------------------------------
/src/checkstyle/detect/DetectableProperty.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.detect;
2 |
3 | typedef DetectableProperty = Any;
--------------------------------------------------------------------------------
/src/checkstyle/detect/DetectablePropertyList.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.detect;
2 |
3 | typedef DetectablePropertyList = {
4 | var propertyName:String;
5 | var values:Array;
6 | }
--------------------------------------------------------------------------------
/src/checkstyle/detect/DetectionReporter.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.detect;
2 |
3 | import checkstyle.reporter.IReporter;
4 |
5 | class DetectionReporter implements IReporter {
6 | public var messageCount:Int;
7 |
8 | public function new() {
9 | messageCount = 0;
10 | }
11 |
12 | public function start() {}
13 |
14 | public function finish() {}
15 |
16 | public function addFile(f:CheckFile) {}
17 |
18 | public function addMessage(m:Message) {
19 | messageCount++;
20 | }
21 | }
--------------------------------------------------------------------------------
/src/checkstyle/detect/DetectionResult.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.detect;
2 |
3 | enum DetectionResult {
4 | NO_CHANGE;
5 | CHANGE_DETECTED(value:Any);
6 | REDUCED_VALUE_LIST(value:Any);
7 | }
--------------------------------------------------------------------------------
/src/checkstyle/errors/Error.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.errors;
2 |
3 | class Error {
4 | public var message(default, null):String;
5 |
6 | public function new(message:String) {
7 | this.message = message;
8 | }
9 |
10 | public function toString():String {
11 | return message;
12 | }
13 | }
--------------------------------------------------------------------------------
/src/checkstyle/errors/InvalidDirectiveError.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.errors;
2 |
3 | class InvalidDirectiveError extends checkstyle.errors.Error {}
--------------------------------------------------------------------------------
/src/checkstyle/import.hx:
--------------------------------------------------------------------------------
1 | package checkstyle;
2 |
3 | import checkstyle.Checker.LinePos;
4 | import checkstyle.detect.DetectableInstances;
5 | import checkstyle.utils.ErrorUtils;
6 | import haxe.Exception;
7 | import haxe.io.Bytes;
8 | import haxe.macro.Expr;
9 | import haxeparser.Data;
10 | import tokentree.TokenTree;
11 | import tokentree.TokenTreeAccessHelper;
12 | import tokentree.TokenTreeDef;
13 | import tokentree.utils.TokenTreeCheckUtils;
14 |
15 | using StringTools;
16 | using checkstyle.utils.ArrayUtils;
17 | using checkstyle.utils.ExprUtils;
18 | using checkstyle.utils.FieldUtils;
19 | using checkstyle.utils.StringUtils;
20 | using tokentree.TokenTreeAccessHelper;
21 |
22 | #if !macro
23 | import checkstyle.SeverityLevel;
24 | #end
--------------------------------------------------------------------------------
/src/checkstyle/reporter/CodeClimateReporter.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.reporter;
2 |
3 | import checkstyle.Message.MessageLocation;
4 | import haxe.Json;
5 |
6 | using StringTools;
7 |
8 | class CodeClimateReporter extends BaseReporter {
9 | static inline var INFO:String = "info";
10 | static inline var NORMAL:String = "normal";
11 | static inline var CRITICAL:String = "critical";
12 | static inline var REMEDIATION_BASE:Int = 50000;
13 |
14 | override public function start() {}
15 |
16 | override public function finish() {}
17 |
18 | override public function addMessage(message:Message) {
19 | Sys.print(Json.stringify(createIssue(message, message)));
20 | Sys.stdout().writeByte(0);
21 | for (related in message.related) {
22 | Sys.print(Json.stringify(createIssue(message, related)));
23 | Sys.stdout().writeByte(0);
24 | }
25 | }
26 |
27 | function createIssue(message:Message, location:MessageLocation):Any {
28 | var file = ~/^\/code\//.replace(location.fileName, "");
29 | file = ~/\/\//.replace(file, "/");
30 |
31 | var issue = {
32 | type: "issue",
33 | check_name: message.moduleName,
34 | description: message.message.replace("\"", "`"),
35 | content: {
36 | body: message.desc
37 | },
38 | severity: getSeverity(message.severity),
39 | categories: message.categories,
40 | remediation_points: message.points * REMEDIATION_BASE,
41 | location: {
42 | path: file,
43 | positions: {
44 | begin: {
45 | line: location.range.start.line,
46 | column: location.range.start.column
47 | },
48 | end: {
49 | line: location.range.end.line,
50 | column: location.range.end.column
51 | }
52 | }
53 | }
54 | };
55 |
56 | return issue;
57 | }
58 |
59 | function getSeverity(severity:SeverityLevel):String {
60 | return switch (severity) {
61 | case "INFO": INFO;
62 | case "WARNING": NORMAL;
63 | case "ERROR": CRITICAL;
64 | default: INFO;
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/src/checkstyle/reporter/ExitCodeReporter.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.reporter;
2 |
3 | class ExitCodeReporter implements IReporter {
4 | var failCheckCount:Int;
5 |
6 | public function new() {
7 | failCheckCount = 0;
8 | }
9 |
10 | public function start() {}
11 |
12 | public function finish() {
13 | Main.setExitCode(failCheckCount);
14 | }
15 |
16 | public function addFile(file:CheckFile) {}
17 |
18 | public function addMessage(message:Message) {
19 | if (message.severity == ERROR) failCheckCount++;
20 | }
21 | }
--------------------------------------------------------------------------------
/src/checkstyle/reporter/IReporter.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.reporter;
2 |
3 | interface IReporter {
4 | // Before any file checked
5 | function start():Void;
6 | // After all files checked
7 | function finish():Void;
8 | // Before file checked
9 | function addFile(file:CheckFile):Void;
10 | // When issue found
11 | function addMessage(message:Message):Void;
12 | }
--------------------------------------------------------------------------------
/src/checkstyle/reporter/JSONReporter.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.reporter;
2 |
3 | import checkstyle.Message.MessageLocation;
4 | import haxe.Json;
5 |
6 | class JSONReporter extends BaseReporter {
7 | var files:Array;
8 |
9 | public function new(fileCount:Int, checkCount:Int, usedCheckCount:Int, path:String, ns:Bool) {
10 | super(fileCount, checkCount, usedCheckCount, path, ns);
11 | files = [];
12 | }
13 |
14 | override public function start() {
15 | super.start();
16 | }
17 |
18 | override public function addFile(f:CheckFile) {
19 | files.push(f.name);
20 | }
21 |
22 | override public function finish() {
23 | var jsonReport:GlobalReport = [];
24 | for (file in files) {
25 | var fileReport:FileReport = makeFileReport(file);
26 | jsonReport.push(fileReport);
27 | }
28 |
29 | if (file != null) report.add(Json.stringify(jsonReport));
30 | super.finish();
31 | }
32 |
33 | function makeFileReport(file:String):FileReport {
34 | var fileReport:FileReport = {
35 | fileName: file,
36 | messages: []
37 | };
38 | for (message in messages) {
39 | if (file == message.fileName) {
40 | fileReport.messages.push(makeReportMessage(message, message));
41 | continue;
42 | }
43 | for (related in message.related) {
44 | if (related.fileName != file) {
45 | continue;
46 | }
47 | fileReport.messages.push(makeReportMessage(message, related));
48 | }
49 | }
50 | return fileReport;
51 | }
52 |
53 | function makeReportMessage(message:Message, location:MessageLocation):ReportMessage {
54 | return {
55 | line: location.range.start.line,
56 | column: location.range.start.column,
57 | severity: BaseReporter.severityString(message.severity),
58 | message: message.message
59 | };
60 | }
61 |
62 | override public function addMessage(message:Message) {
63 | super.addMessage(message);
64 | switch (message.severity) {
65 | case ERROR:
66 | errors++;
67 | case WARNING:
68 | warnings++;
69 | case INFO:
70 | infos++;
71 | default:
72 | }
73 |
74 | Sys.print(applyColour(getMessage(message).toString(), message.severity));
75 | }
76 | }
77 |
78 | typedef ReportMessage = {
79 | var line:Int;
80 | var column:Int;
81 | var severity:String;
82 | var message:String;
83 | };
84 |
85 | typedef FileReport = {
86 | var fileName:String;
87 | var messages:Array;
88 | };
89 |
90 | typedef GlobalReport = Array;
--------------------------------------------------------------------------------
/src/checkstyle/reporter/ProgressReporter.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.reporter;
2 |
3 | class ProgressReporter implements IReporter {
4 | var lineLength:Int;
5 | var numFiles:Int;
6 |
7 | public function new(numFiles:Int) {
8 | this.numFiles = numFiles;
9 | }
10 |
11 | public function start() {}
12 |
13 | public function finish() {
14 | clear();
15 | }
16 |
17 | public function addFile(f:CheckFile) {
18 | clear();
19 | var percentage = Math.floor((f.index + 1) / numFiles * 100);
20 | var line = '${percentage}% - ${f.name}';
21 | lineLength = line.length;
22 | Sys.print(line);
23 |
24 | if (f.index == numFiles - 1) Sys.print("\n");
25 | }
26 |
27 | function clear() {
28 | Sys.print("\r");
29 | for (count in 0...lineLength) Sys.print(" ");
30 | Sys.print("\r");
31 | }
32 |
33 | public function addMessage(m:Message) {}
34 | }
--------------------------------------------------------------------------------
/src/checkstyle/reporter/TextReporter.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.reporter;
2 |
3 | import haxe.io.Output;
4 |
5 | class TextReporter extends BaseReporter {
6 | override public function addMessage(message:Message) {
7 | var sb:StringBuf = getMessage(message);
8 | var output:Output = Sys.stderr();
9 |
10 | switch (message.severity) {
11 | case ERROR:
12 | errors++;
13 | case WARNING:
14 | warnings++;
15 | case INFO:
16 | infos++;
17 | output = Sys.stdout();
18 | default:
19 | }
20 |
21 | var line = sb.toString();
22 | if (Sys.systemName() == "Windows") output.writeString(line);
23 | else Sys.print(applyColour(line, message.severity));
24 | if (file != null) report.add(line);
25 | }
26 | }
--------------------------------------------------------------------------------
/src/checkstyle/utils/ArrayUtils.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.utils;
2 |
3 | import haxe.ds.ArraySort;
4 |
5 | class ArrayUtils {
6 | public static inline function contains(a:Array, el:T):Bool {
7 | return a.indexOf(el) != -1;
8 | }
9 |
10 | public static inline function sortStrings(texts:Array) {
11 | ArraySort.sort(texts, function(a:String, b:String):Int {
12 | if (a > b) return 1;
13 | if (a < b) return -1;
14 | return 0;
15 | });
16 | }
17 | }
--------------------------------------------------------------------------------
/src/checkstyle/utils/DummyMutex.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.utils;
2 |
3 | class DummyMutex {
4 | public function new() {}
5 |
6 | public function acquire() {}
7 |
8 | public function release() {}
9 | }
--------------------------------------------------------------------------------
/src/checkstyle/utils/DummyThread.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.utils;
2 |
3 | class DummyThread {
4 | public static function create(f:Void -> Void) {
5 | f();
6 | }
7 | }
--------------------------------------------------------------------------------
/src/checkstyle/utils/ErrorUtils.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.utils;
2 |
3 | #if debug
4 | import haxe.CallStack;
5 | #end
6 | import checkstyle.reporter.ReporterManager;
7 |
8 | class ErrorUtils {
9 | public static function handleException(e:Any, file:CheckFile, name:String) {
10 | #if debug
11 | Sys.println(e);
12 | Sys.println("File: " + file.name);
13 | Sys.println("Stacktrace: " + CallStack.toString(CallStack.exceptionStack()));
14 | #end
15 | #if unittest
16 | throw e;
17 | #end
18 | ReporterManager.INSTANCE.addError(file, e, name);
19 | }
20 | }
--------------------------------------------------------------------------------
/src/checkstyle/utils/FieldUtils.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.utils;
2 |
3 | class FieldUtils {
4 | public static function isPublic(f:Field, p:ParentType):Bool {
5 | if (f.access.contains(APublic)) return true;
6 | if (f.access.contains(APrivate)) return false;
7 | return !isDefaultPrivate(f, p);
8 | }
9 |
10 | public static function isPrivate(f:Field, p:ParentType):Bool {
11 | if (f.access.contains(APrivate)) return true;
12 | if (f.access.contains(APublic)) return false;
13 | return isDefaultPrivate(f, p);
14 | }
15 |
16 | public static function isInline(f:Field, p:ParentType):Bool {
17 | return f.access.contains(AInline) || p.kind == ENUM_ABSTRACT;
18 | }
19 |
20 | public static function isStatic(f:Field, p:ParentType):Bool {
21 | return f.access.contains(AStatic);
22 | }
23 |
24 | public static function isAbstract(f:Field, p:ParentType):Bool {
25 | return f.access.contains(AAbstract);
26 | }
27 |
28 | public static function isDefaultPrivate(f:Field, p:ParentType):Bool {
29 | if (p.kind == INTERFACE) return false;
30 | if (p.kind == ENUM_ABSTRACT && !f.access.contains(AStatic) && f.kind.match(FVar(_, _))) return false;
31 | switch (p.decl) {
32 | case EClass(d):
33 | if (d.meta.hasMeta(":publicFields")) return false;
34 | case _:
35 | }
36 | return true;
37 | }
38 |
39 | public static inline function isGetter(f:Field):Bool {
40 | return f.name.startsWith("get_");
41 | }
42 |
43 | public static inline function isSetter(f:Field):Bool {
44 | return f.name.startsWith("set_");
45 | }
46 |
47 | public static inline function isConstructor(f:Field):Bool {
48 | return f.name == "new";
49 | }
50 |
51 | public static function toParentType(decl:TypeDef):ParentType {
52 | switch (decl) {
53 | case EClass(d):
54 | var kind = d.flags.contains(HInterface) ? INTERFACE : CLASS;
55 | return {decl: decl, kind: kind};
56 | case EAbstract(a):
57 | var metaName = #if (haxeparser > "3.2.0") ":enum" #else ":kwdenum" #end;
58 | var kind = a.meta.hasMeta(metaName) ? ENUM_ABSTRACT : ABSTRACT;
59 | for (flag in a.flags) {
60 | switch (flag) {
61 | case AbEnum:
62 | kind = ENUM_ABSTRACT;
63 | default:
64 | }
65 | }
66 | return {decl: decl, kind: kind};
67 | case ETypedef(d):
68 | return {decl: decl, kind: TYPEDEF};
69 | default:
70 | return null;
71 | }
72 | }
73 | }
74 |
75 | enum FieldParentKind {
76 | CLASS;
77 | INTERFACE;
78 | ABSTRACT;
79 | ENUM_ABSTRACT;
80 | TYPEDEF;
81 | }
82 |
83 | typedef ParentType = {
84 | var decl:haxeparser.Data.TypeDef;
85 | var kind:FieldParentKind;
86 | }
--------------------------------------------------------------------------------
/src/checkstyle/utils/Mutex.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.utils;
2 |
3 | #if (neko || macro || eval || cpp || hl || java)
4 | typedef Mutex = sys.thread.Mutex;
5 | #else
6 | typedef Mutex = DummyMutex;
7 | #end
--------------------------------------------------------------------------------
/src/checkstyle/utils/PosHelper.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.utils;
2 |
3 | class PosHelper {
4 | /**
5 | make a position for AST based checks that only holds function signature
6 | @param field determine position for field
7 | @return Position position that holds function signature
8 | **/
9 | public static function makeFieldSignaturePosition(field:Field):Position {
10 | var pos:Position = {file: field.pos.file, min: field.pos.min, max: field.pos.max};
11 | switch (field.kind) {
12 | case FFun(fun):
13 | if (fun.expr != null) {
14 | pos.max = fun.expr.pos.min;
15 | }
16 | case FVar(_):
17 | case FProp(_):
18 | }
19 | return pos;
20 | }
21 |
22 | /**
23 | report function signature not body
24 | @param token function or var token
25 | @return Position token position without body
26 | **/
27 | public static function getReportPos(token:TokenTree):Position {
28 | var pos:Position = token.getPos();
29 | var body:Null = token.access().firstChild().firstOf(POpen).token;
30 | if (body == null) return pos;
31 | body = body.nextSibling;
32 | if (body == null) return pos;
33 | switch (body.tok) {
34 | case BrOpen:
35 | case DblDot:
36 | body = body.nextSibling;
37 | default:
38 | return pos;
39 | }
40 | if (body == null) return pos;
41 | pos.max = body.pos.min;
42 | return pos;
43 | }
44 | }
--------------------------------------------------------------------------------
/src/checkstyle/utils/StringUtils.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.utils;
2 |
3 | class StringUtils {
4 | public static function isStringInterpolation(s:String, fileContent:byte.ByteData, pos:Position):Bool {
5 | var code:Bytes = cast fileContent;
6 | var quote:String = code.sub(pos.min, 1).toString();
7 | if (quote != "'") return false;
8 | var regex:EReg = ~/(^|[^$])\$(\{|[a-zA-Z0-9_]+)/;
9 | return regex.match(s);
10 | }
11 |
12 | public static function isEmpty(s:Null):Bool {
13 | return (s == null) || (s.length <= 0);
14 | }
15 | }
--------------------------------------------------------------------------------
/src/checkstyle/utils/Thread.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.utils;
2 |
3 | #if (neko || macro || eval || cpp || hl || java)
4 | typedef Thread = sys.thread.Thread;
5 | #else
6 | typedef Thread = DummyThread;
7 | #end
--------------------------------------------------------------------------------
/test.hxml:
--------------------------------------------------------------------------------
1 | build/commonTest.hxml
2 | -x TestMain
3 |
--------------------------------------------------------------------------------
/test/TestMain.hx:
--------------------------------------------------------------------------------
1 | import checkstyle.checks.CheckTestCase;
2 | import checkstyle.config.ConfigParserTest;
3 | import checkstyle.config.ExcludeManagerTest;
4 | import checkstyle.detect.DetectCodingStyleTest;
5 | import misc.CheckerTest;
6 | import misc.ThreadTest;
7 | import sys.io.File;
8 | import utest.Runner;
9 | import utest.ui.text.DiagnosticsReport;
10 |
11 | class TestMain {
12 | public function new() {
13 | var runner:Runner = new Runner();
14 |
15 | var failed = false;
16 | runner.onProgress.add(r -> {
17 | if (!r.result.allOk()) {
18 | failed = true;
19 | }
20 | });
21 | runner.onComplete.add(_ -> {
22 | completionHandler(!failed);
23 | });
24 |
25 | new DiagnosticsReport(runner);
26 |
27 | var testClasses = CompileTime.getAllClasses(CheckTestCase);
28 | for (test in testClasses) {
29 | runner.addCase(Type.createInstance(test, []));
30 | }
31 |
32 | runner.addCase(new CheckerTest());
33 | runner.addCase(new ConfigParserTest());
34 | runner.addCase(new DetectCodingStyleTest());
35 | runner.addCase(new ThreadTest());
36 |
37 | runner.run();
38 | }
39 |
40 | function completionHandler(success:Bool) {
41 | #if instrument
42 | instrument.coverage.Coverage.endCoverage();
43 | #end
44 | }
45 |
46 | static function main() {
47 | new TestMain();
48 | }
49 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/block/BlockTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.block;
2 |
3 | // tests for blocks using multiple check classes
4 | class BlockTest extends CheckTestCase {
5 | @Test
6 | public function testBlockFormatIssue42() {
7 | var check:EmptyBlockCheck = new EmptyBlockCheck();
8 | assertNoMsg(check, ISSUE_42);
9 | assertNoMsg(check, ISSUE_42_MACRO);
10 | assertNoMsg(check, CONDITIONAL_TEST);
11 |
12 | var checkLeft:LeftCurlyCheck = new LeftCurlyCheck();
13 | checkLeft.option = NL;
14 | assertNoMsg(checkLeft, ISSUE_42);
15 | assertNoMsg(checkLeft, ISSUE_42_MACRO);
16 |
17 | var checkRight:RightCurlyCheck = new RightCurlyCheck();
18 | assertNoMsg(checkRight, ISSUE_42);
19 | assertNoMsg(checkRight, ISSUE_42_MACRO);
20 | assertNoMsg(checkRight, CONDITIONAL_TEST);
21 | }
22 |
23 | @Test
24 | public function testBlockFormatIssue42Eol() {
25 | var check:EmptyBlockCheck = new EmptyBlockCheck();
26 | assertNoMsg(check, ISSUE_42_MACRO_EOL);
27 |
28 | var checkLeft:LeftCurlyCheck = new LeftCurlyCheck();
29 | assertNoMsg(checkLeft, ISSUE_42_MACRO_EOL);
30 |
31 | var checkRight:RightCurlyCheck = new RightCurlyCheck();
32 | assertNoMsg(checkRight, ISSUE_42_MACRO_EOL);
33 | }
34 | }
35 |
36 | enum abstract BlockTests(String) to String {
37 | var ISSUE_42 = "
38 | abstractAndClass Macro
39 | {
40 | function build()
41 | {
42 | return
43 | {
44 | while (true)
45 | trace('');
46 | }
47 | }
48 | }";
49 | var ISSUE_42_MACRO = "
50 | abstractAndClass Macro
51 | {
52 | function build()
53 | {
54 | return macro
55 | {
56 | while (true)
57 | trace('');
58 | }
59 | }
60 | }";
61 | var ISSUE_42_MACRO_EOL = "
62 | abstractAndClass Macro {
63 | function build() {
64 | return macro {
65 | while (true)
66 | trace('');
67 | }
68 | }
69 | }";
70 | var CONDITIONAL_TEST = "
71 | abstractAndClass Test {
72 | #if false
73 | function build() {
74 | #else
75 | function build2() {
76 | #end
77 | }
78 |
79 | function test() {
80 | #if debug
81 | try {
82 | #end
83 |
84 | #if debug
85 | catch(e) {
86 | // nothing
87 | }
88 | #end
89 | }
90 | }";
91 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/coding/AvoidTernaryOperatorCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | import checkstyle.SeverityLevel;
4 |
5 | class AvoidTernaryOperatorCheckTest extends CheckTestCase {
6 | @Test
7 | public function testInlineCondition() {
8 | var check = new AvoidTernaryOperatorCheck();
9 | check.severity = SeverityLevel.INFO;
10 | assertMsg(check, TEST1, "Avoid ternary operator");
11 | }
12 | }
13 |
14 | enum abstract AvoidTernaryOperatorCheckTests(String) to String {
15 | var TEST1 = "
16 | abstractAndClass Test {
17 | var a:Array = [];
18 | var x = (a == null || a.length < 1) ? null : a[0];
19 | }";
20 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/coding/DefaultComesLastCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | class DefaultComesLastCheckTest extends CheckTestCase {
4 | static inline var MSG:String = 'Default should be last label in the "switch"';
5 |
6 | @Test
7 | public function testFirstDefault() {
8 | assertMsg(new DefaultComesLastCheck(), TEST1, MSG);
9 | }
10 |
11 | @Test
12 | public function testMiddleDefault() {
13 | assertMsg(new DefaultComesLastCheck(), TEST2, MSG);
14 | }
15 |
16 | @Test
17 | public function testLastDefault() {
18 | assertNoMsg(new DefaultComesLastCheck(), TEST3);
19 | }
20 | }
21 |
22 | enum abstract DefaultComesLastCheckTests(String) to String {
23 | var TEST1 = "
24 | abstractAndClass Test {
25 |
26 | function test() {
27 | var a =1;
28 | switch(a) {
29 | default: trace('test');
30 | case 1:
31 | case 4:
32 | }
33 | }
34 | }";
35 | var TEST2 = "
36 | abstractAndClass Test {
37 |
38 | function test() {
39 | var a =1;
40 | switch(a) {
41 | case 1:
42 | default: trace('test');
43 | case 4:
44 | }
45 | }
46 | }";
47 | var TEST3 = "
48 | abstractAndClass Test {
49 |
50 | function test() {
51 | var a =1;
52 | switch(a) {
53 | case 1:
54 | case 4:
55 | default: trace('test');
56 | }
57 | }
58 | }";
59 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/coding/MultipleVariableDeclarationsCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | class MultipleVariableDeclarationsCheckTest extends CheckTestCase {
4 | static inline var MSG_MULTI_VAR_COMMA:String = "Each variable declaration must be in its own statement";
5 | static inline var MSG_MULTI_VAR:String = "Only one variable definition per line allowed";
6 |
7 | @Test
8 | public function testMultiVarsStatement() {
9 | assertMsg(new MultipleVariableDeclarationsCheck(), TEST1, MSG_MULTI_VAR_COMMA);
10 | assertMsg(new MultipleVariableDeclarationsCheck(), TEST2, MSG_MULTI_VAR_COMMA);
11 | }
12 |
13 | @Test
14 | public function testMultiVarsInOneLine() {
15 | assertMessages(new MultipleVariableDeclarationsCheck(), TEST3, [MSG_MULTI_VAR, MSG_MULTI_VAR, MSG_MULTI_VAR]);
16 | }
17 |
18 | @Test
19 | public function testCorrectVariables() {
20 | assertNoMsg(new MultipleVariableDeclarationsCheck(), TEST4);
21 | assertNoMsg(new MultipleVariableDeclarationsCheck(), TEST5);
22 | }
23 | }
24 |
25 | enum abstract MultipleVariableDeclarationsCheckTests(String) to String {
26 | var TEST1 = "
27 | abstractAndClass Test {
28 | function a() {
29 | var d,e = 2;
30 | }
31 | }";
32 | var TEST2 = "
33 | abstractAndClass Test {
34 | function a() {
35 | var d,e,f;
36 | }
37 | }";
38 | var TEST3 = "
39 | abstractAndClass Test {
40 | function a() {
41 | var d = 10; var e;
42 | var d;var e;
43 | var f; var g;
44 | }
45 | }";
46 | var TEST4 = "
47 | abstractAndClass Test {
48 | function a() {
49 | var d;
50 | var e = 2;
51 | }
52 | }";
53 | var TEST5 = "
54 | abstractAndClass Test {
55 | function foo() {
56 | var s = 'var f';
57 | }
58 | }";
59 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/coding/NestedForDepthCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | class NestedForDepthCheckTest extends CheckTestCase {
4 | @Test
5 | public function testDefault() {
6 | var check = new NestedForDepthCheck();
7 | assertNoMsg(check, TEST1);
8 | }
9 |
10 | @Test
11 | public function testDefaultTooMany() {
12 | var check = new NestedForDepthCheck();
13 | assertMsg(check, TEST2, "Nested loop depth is 2 (max allowed is 1)");
14 | }
15 |
16 | @Test
17 | public function testMaxParameter() {
18 | var check = new NestedForDepthCheck();
19 | check.max = 2;
20 |
21 | assertNoMsg(check, TEST1);
22 | assertNoMsg(check, TEST2);
23 |
24 | check.max = 0;
25 | assertNoMsg(check, TEST1);
26 | assertMsg(check, TEST2, "Nested loop depth is 1 (max allowed is 0)");
27 | }
28 | }
29 |
30 | enum abstract NestedForDepthCheckTests(String) to String {
31 | var TEST1 = "
32 | abstractAndClass Test {
33 | public function test(params:Array):Void {
34 | for (param in params) trace(param); // level 0
35 | for (i in 0...params.length) { // level 0
36 | trace ('$i ${params[i]}');
37 | }
38 | }
39 |
40 | @SuppressWarnings('checkstyle:NestedForDepth')
41 | public function test2(param:Array) {
42 | for (outerParam in params) { // level 0
43 | for (middleParam in params) { // level 1
44 | for (innerParam in params) { // level 2
45 | if (outerParam == innerParam) {
46 | trace (param);
47 | }
48 | }
49 | }
50 | }
51 | }
52 | }
53 |
54 | @SuppressWarnings('checkstyle:NestedForDepth')
55 | abstractAndClass Test2 {
56 | public function test2(param:Array) {
57 | for (outerParam in params) { // level 0
58 | for (middleParam in params) { // level 1
59 | for (innerParam in params) { // level 2
60 | if (outerParam == innerParam) {
61 | trace (param);
62 | }
63 | }
64 | }
65 | }
66 | }
67 | }";
68 | var TEST2 = "
69 | abstractAndClass Test {
70 | public function test1(param:Array) {
71 | for (outerParam in params) { // level 0
72 | for (middleParam in params) { // level 1
73 | for (innerParam in params) { // level 2
74 | if (outerParam == innerParam) {
75 | trace (param);
76 | }
77 | }
78 | }
79 | }
80 | }
81 | }";
82 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/coding/NestedIfDepthCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | class NestedIfDepthCheckTest extends CheckTestCase {
4 | @Test
5 | public function testDefault() {
6 | var check = new NestedIfDepthCheck();
7 | assertNoMsg(check, TEST1);
8 | }
9 |
10 | @Test
11 | public function testDefaultTooMany() {
12 | var check = new NestedIfDepthCheck();
13 | assertMsg(check, TEST2, "Nested if-else depth is 2 (max allowed is 1)");
14 | }
15 |
16 | @Test
17 | public function testMaxParameter() {
18 | var check = new NestedIfDepthCheck();
19 | check.max = 2;
20 |
21 | assertNoMsg(check, TEST1);
22 | assertNoMsg(check, TEST2);
23 |
24 | check.max = 0;
25 | assertNoMsg(check, TEST1);
26 | assertMsg(check, TEST2, "Nested if-else depth is 1 (max allowed is 0)");
27 | }
28 | }
29 |
30 | enum abstract NestedIfDepthCheckTests(String) to String {
31 | var TEST1 = "
32 | abstractAndClass Test {
33 | public function test(param:Int):Void {
34 | if (param == 0) return 0; // level 0
35 | if (param == 1) { // level 0
36 | return 1;
37 | }
38 | else {
39 | return 2;
40 | }
41 | }
42 |
43 | @SuppressWarnings('checkstyle:NestedIfDepth')
44 | public function test1(param:Int) {
45 | if (param == 1) { // level 0
46 | return 1;
47 | }
48 | else {
49 | if ((param == 2) || (param == 3)) { // level 1
50 | if (param == 3) return 3; // level 2
51 | return 2;
52 | }
53 | }
54 | return 3;
55 | }
56 | }";
57 | var TEST2 = "
58 | abstractAndClass Test {
59 | public function test1(param:Int) {
60 | if (param == 1) { // level 0
61 | return 1;
62 | }
63 | else {
64 | if ((param == 2) || (param == 3)) { // level 1
65 | if (param == 3) return 3; // level 2
66 | return 2;
67 | }
68 | }
69 | return 3;
70 | }
71 | }";
72 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/coding/NestedTryDepthCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | class NestedTryDepthCheckTest extends CheckTestCase {
4 | static inline var NESTED_TRY_DEPTH_IS_2_MAX_ALLOWED_IS_1:String = "Nested try depth is 2 (max allowed is 1)";
5 | static inline var NESTED_TRY_DEPTH_IS_1_MAX_ALLOWED_IS_0:String = "Nested try depth is 1 (max allowed is 0)";
6 |
7 | @Test
8 | public function testDefault() {
9 | var check = new NestedTryDepthCheck();
10 | assertNoMsg(check, TEST1);
11 | }
12 |
13 | @Test
14 | public function testDefaultTooMany() {
15 | var check = new NestedTryDepthCheck();
16 | assertMessages(check, TEST2, [NESTED_TRY_DEPTH_IS_2_MAX_ALLOWED_IS_1, NESTED_TRY_DEPTH_IS_2_MAX_ALLOWED_IS_1]);
17 | }
18 |
19 | @Test
20 | public function testMaxParameter() {
21 | var check = new NestedTryDepthCheck();
22 | check.max = 2;
23 |
24 | assertNoMsg(check, TEST1);
25 | assertNoMsg(check, TEST2);
26 |
27 | check.max = 0;
28 | assertNoMsg(check, TEST1);
29 | assertMessages(check, TEST2, [
30 | NESTED_TRY_DEPTH_IS_1_MAX_ALLOWED_IS_0,
31 | NESTED_TRY_DEPTH_IS_1_MAX_ALLOWED_IS_0,
32 | NESTED_TRY_DEPTH_IS_1_MAX_ALLOWED_IS_0,
33 | NESTED_TRY_DEPTH_IS_1_MAX_ALLOWED_IS_0,
34 | NESTED_TRY_DEPTH_IS_1_MAX_ALLOWED_IS_0,
35 | NESTED_TRY_DEPTH_IS_1_MAX_ALLOWED_IS_0
36 | ]);
37 | }
38 | }
39 |
40 | enum abstract NestedTryDepthCheckTests(String) to String {
41 | var TEST1 = "
42 | abstractAndClass Test {
43 | public function test() {
44 | try { } catch(e:String) { } // level 0
45 | try { // level 0
46 | throw 'test';
47 | } catch(e:String) {
48 | }
49 | }
50 |
51 | @SuppressWarnings('checkstyle:NestedTryDepth')
52 | public function test1() {
53 | try { // level 0
54 | try { // level 0
55 | throw 'test';
56 | } catch(e:String) {
57 | throw 'test';
58 | }
59 | } catch(e:String) {
60 | try { // level 1
61 | } catch(e1:String) {
62 | try { // level 2
63 | } catch(e1:String) {
64 | }
65 | }
66 | } catch(e1:Int) {
67 | try { // level 1
68 | } catch(e2:String) {
69 | }
70 | }
71 | }
72 | }";
73 | var TEST2 = "
74 | abstractAndClass Test {
75 | public function test1() {
76 | try { // level 0
77 | try { // level 0
78 | throw 'test';
79 | } catch(e:String) {
80 | throw 'test';
81 | }
82 | } catch(e:String) {
83 | try { // level 1
84 | } catch(e1:String) {
85 | try { // level 2
86 | } catch(e1:String) {
87 | }
88 | }
89 | } catch(e1:Int) {
90 | try { // level 1
91 | } catch(e2:String) {
92 | }
93 | }
94 | }
95 | }";
96 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/coding/NullableParameterCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | import checkstyle.checks.CheckTestCase;
4 |
5 | class NullableParameterCheckTest extends CheckTestCase {
6 | @Test
7 | function testQuestionMark() {
8 | var check = new NullableParameterCheck();
9 | check.option = QUESTION_MARK;
10 |
11 | assertNoMsg(check, NO_DEFAULT);
12 | assertNoMsg(check, DEFAULT);
13 | assertMsg(check, NULL_DEFAULT, 'Function parameter "arg = null" should be "?arg"');
14 | assertNoMsg(check, OPTIONAL);
15 | assertMsg(check, OPTIONAL_WITH_NULL_DEFAULT, 'Function parameter "?arg = null" should be "?arg"');
16 | assertNoMsg(check, OPTIONAL_WITH_NON_NULL_DEFAULT);
17 | }
18 |
19 | @Test
20 | function testNullDefault() {
21 | var check = new NullableParameterCheck();
22 | check.option = NULL_DEFAULT;
23 |
24 | assertNoMsg(check, NO_DEFAULT);
25 | assertNoMsg(check, DEFAULT);
26 | assertNoMsg(check, NULL_DEFAULT);
27 | assertMsg(check, OPTIONAL, 'Function parameter "?arg" should be "arg = null"');
28 | assertMsg(check, OPTIONAL_WITH_NULL_DEFAULT, 'Function parameter "?arg = null" should be "arg = null"');
29 | assertNoMsg(check, OPTIONAL_WITH_NON_NULL_DEFAULT);
30 | }
31 | }
32 |
33 | enum abstract NullableParameterCheckTests(String) to String {
34 | var NO_DEFAULT = "
35 | class Test {
36 | function foo(arg:Int) {}
37 | }";
38 | var DEFAULT = "
39 | class Test {
40 | function foo(arg:Int = 0) {}
41 | }";
42 | var NULL_DEFAULT = "
43 | class Test {
44 | function foo(arg:Int = null) {}
45 | }";
46 | var OPTIONAL = "
47 | class Test {
48 | function foo(?arg:Int) {}
49 | }";
50 | var OPTIONAL_WITH_NULL_DEFAULT = "
51 | class Test {
52 | function foo(?arg:Int = null) {}
53 | }";
54 | var OPTIONAL_WITH_NON_NULL_DEFAULT = "
55 | class Test {
56 | function foo(?arg:Int = 0) {}
57 | }";
58 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/coding/ReturnCountCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | class ReturnCountCheckTest extends CheckTestCase {
4 | @Test
5 | public function testReturnCount() {
6 | assertMsg(new ReturnCountCheck(), TEST1, "Return count is 3 (max allowed is 2)");
7 | }
8 |
9 | @Test
10 | public function testCorrectReturnCount() {
11 | assertNoMsg(new ReturnCountCheck(), TEST2);
12 | }
13 |
14 | @Test
15 | public function testSuppressedReturnCount() {
16 | assertNoMsg(new ReturnCountCheck(), TEST3);
17 | }
18 |
19 | @Test
20 | public function testCustomReturnCount() {
21 | var check = new ReturnCountCheck();
22 | check.max = 1;
23 | assertMsg(check, TEST4, "Return count is 2 (max allowed is 1)");
24 | }
25 |
26 | @Test
27 | public function testIgnoreRE() {
28 | var check = new ReturnCountCheck();
29 | check.ignoreFormat = "^equals$";
30 | assertNoMsg(check, TEST5);
31 | }
32 |
33 | @Test
34 | public function testClosure() {
35 | assertNoMsg(new ReturnCountCheck(), RETURN_IN_CLOSURE);
36 | assertMsg(new ReturnCountCheck(), RETURN_IN_CLOSURE_2, "Return count is 3 (max allowed is 2)");
37 | }
38 | }
39 |
40 | enum abstract ReturnCountCheckTests(String) to String {
41 | var TEST1 = "
42 | abstractAndClass Test {
43 | function a() {
44 | return 1;
45 | return 2;
46 | return 3;
47 | }
48 | }";
49 | var TEST2 = "
50 | abstractAndClass Test {
51 | function a() {
52 | return 1;
53 | if (true) {
54 | return 2;
55 | }
56 | }
57 | }";
58 | var TEST3 = "
59 | abstractAndClass Test {
60 | @SuppressWarnings('checkstyle:ReturnCount')
61 | function a() {
62 | return 1;
63 | if (true) {
64 | return 2;
65 | }
66 | else return 3;
67 | }
68 | }";
69 | var TEST4 = "
70 | abstractAndClass Test {
71 | function a() {
72 | return 1;
73 | if (true) {
74 | return 2;
75 | }
76 | }
77 | }";
78 | var TEST5 = "
79 | abstractAndClass Test {
80 | function equals() {
81 | return 1;
82 | return 2;
83 | return 3;
84 | }
85 | }";
86 | var RETURN_IN_CLOSURE = "
87 | abstractAndClass Test {
88 | function equals() {
89 | var a = function() { return 1; };
90 | var b = function() { return 2; };
91 | return a() + b();
92 | }
93 | }";
94 | var RETURN_IN_CLOSURE_2 = "
95 | abstractAndClass Test {
96 | function equals() {
97 | var a = function() {
98 | return 1;
99 | return 2;
100 | return 3;
101 | }
102 | var b = function() { return 2; };
103 | return a() + b();
104 | }
105 | }";
106 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/coding/SimplifyBooleanExpressionCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | class SimplifyBooleanExpressionCheckTest extends CheckTestCase {
4 | static inline var MSG_SIMPLIFY:String = "Boolean expression can be simplified";
5 |
6 | @Test
7 | public function testWrongExpression() {
8 | assertMsg(new SimplifyBooleanExpressionCheck(), TEST1, MSG_SIMPLIFY);
9 | assertMsg(new SimplifyBooleanExpressionCheck(), TEST2, MSG_SIMPLIFY);
10 | assertMsg(new SimplifyBooleanExpressionCheck(), TEST3, MSG_SIMPLIFY);
11 | assertMsg(new SimplifyBooleanExpressionCheck(), TEST4, MSG_SIMPLIFY);
12 | }
13 |
14 | @Test
15 | public function testCorrectExpression() {
16 | assertNoMsg(new SimplifyBooleanExpressionCheck(), TEST5);
17 | assertNoMsg(new SimplifyBooleanExpressionCheck(), TEST6);
18 | }
19 |
20 | @Test
21 | public function testSuppressExpression() {
22 | assertNoMsg(new SimplifyBooleanExpressionCheck(), TEST7);
23 | }
24 | }
25 |
26 | enum abstract SimplifyBooleanExpressionCheckTests(String) to String {
27 | var TEST1 = "
28 | abstractAndClass Test {
29 | function test() {
30 | var bvar:Bool;
31 | if (bvar == true) {}
32 | }
33 | }";
34 | var TEST2 = "
35 | abstractAndClass Test {
36 | function test() {
37 | var bvar:Bool;
38 | if (bvar || true) {}
39 | }
40 | }";
41 | var TEST3 = "
42 | abstractAndClass Test {
43 | function test() {
44 | var bvar:Bool;
45 | if (bvar != true) {}
46 | }
47 | }";
48 | var TEST4 = "
49 | abstractAndClass Test {
50 | function test() {
51 | var bvar:Bool;
52 | if (!false) {}
53 | }
54 | }";
55 | var TEST5 = "
56 | abstractAndClass Test {
57 | function test() {
58 | var bvar:Bool;
59 | if (bvar) {}
60 | }
61 | }";
62 | var TEST6 = "
63 | abstractAndClass Test {
64 | function test() {
65 | var bvar:Bool;
66 | if (!bvar) {}
67 | }
68 | }";
69 | var TEST7 = "
70 | abstractAndClass Test {
71 | @SuppressWarnings('checkstyle:SimplifyBooleanExpression')
72 | public static function main() {
73 | var value: Null = null;
74 | trace(value == true);
75 | }
76 | }";
77 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/coding/SimplifyBooleanReturnCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | class SimplifyBooleanReturnCheckTest extends CheckTestCase {
4 | static inline var MSG_SIMPLIFY:String = "Conditional logic can be removed";
5 |
6 | @Test
7 | public function testWrongExpression() {
8 | assertMsg(new SimplifyBooleanReturnCheck(), TEST1, MSG_SIMPLIFY);
9 | }
10 |
11 | @Test
12 | public function testCorrectExpression() {
13 | assertNoMsg(new SimplifyBooleanReturnCheck(), TEST2);
14 | }
15 |
16 | @Test
17 | public function testOnlyIfExpression() {
18 | assertNoMsg(new SimplifyBooleanReturnCheck(), TEST3);
19 | }
20 | }
21 |
22 | enum abstract SimplifyBooleanReturnCheckTests(String) to String {
23 | var TEST1 = "
24 | abstractAndClass Test {
25 | function test() {
26 | var a = (10 / 5 == 2);
27 | if (a) return false;
28 | else return true;
29 | }
30 | }";
31 | var TEST2 = "
32 | abstractAndClass Test {
33 | function test() {
34 | var a = (10 / 5 == 2);
35 | return a;
36 | }
37 | }";
38 | var TEST3 = "
39 | abstractAndClass Test {
40 | function test() {
41 | var a = (10 / 5 == 2);
42 | if (a) return false;
43 | }
44 | }";
45 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/coding/TraceCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | import checkstyle.SeverityLevel;
4 |
5 | class TraceCheckTest extends CheckTestCase {
6 | static inline var MSG_TRACE_DETECTED:String = "Trace detected";
7 |
8 | @Test
9 | public function testTrace() {
10 | var check = new TraceCheck();
11 | check.severity = SeverityLevel.INFO;
12 | assertMsg(check, TRACE_TEXT, MSG_TRACE_DETECTED);
13 | assertMsg(check, TRACE_VAR, MSG_TRACE_DETECTED);
14 | }
15 |
16 | @Test
17 | public function testNotATrace() {
18 | var check = new TraceCheck();
19 | check.severity = SeverityLevel.INFO;
20 | assertNoMsg(check, CUSTOM_TRACE);
21 | assertNoMsg(check, TRACE_FUNCTION);
22 | }
23 |
24 | @Test
25 | public function testSuppressedTrace() {
26 | var check = new TraceCheck();
27 | check.severity = SeverityLevel.INFO;
28 | assertNoMsg(check, TRACE_SUPPRESSED);
29 | }
30 | }
31 |
32 | enum abstract TraceCheckTests(String) to String {
33 | var TRACE_TEXT = "
34 | abstractAndClass Test {
35 | function a() {
36 | trace('test');
37 | }
38 | }";
39 | var TRACE_VAR = "
40 | abstractAndClass Test {
41 | function a(x) {
42 | trace(x);
43 | }
44 | }";
45 | var TRACE_SUPPRESSED = "
46 | abstractAndClass Test {
47 | @SuppressWarnings('checkstyle:Trace')
48 | function a() {
49 | trace(x);
50 | trace('test');
51 | }
52 | }";
53 | var TRACE_FUNCTION = "
54 | abstractAndClass Test {
55 | function trace(x) {
56 | }
57 | }";
58 | var CUSTOM_TRACE = "
59 | abstractAndClass Test {
60 | function equals() {
61 | custom.trace('test');
62 | }
63 | }";
64 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/coding/UnusedLocalVarCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | class UnusedLocalVarCheckTest extends CheckTestCase {
4 | static inline var MSG_UNUSED_VAR_INDEX:String = "Unused local variable index";
5 |
6 | @Test
7 | public function testLocalVar() {
8 | var check = new UnusedLocalVarCheck();
9 | assertNoMsg(check, USED_INDEX);
10 | assertNoMsg(check, STRING_INTERPOLATION);
11 | assertNoMsg(check, MACRO);
12 | }
13 |
14 | @Test
15 | public function testUnusedLocalVar() {
16 | var check = new UnusedLocalVarCheck();
17 | assertMsg(check, UNUSED_INDEX, MSG_UNUSED_VAR_INDEX);
18 | assertMsg(check, UNUSED_INDEX2, MSG_UNUSED_VAR_INDEX);
19 | assertMsg(check, STRING_INTERPOLATION_UNUSED, MSG_UNUSED_VAR_INDEX);
20 | assertMsg(check, MACRO_UNUSED, MSG_UNUSED_VAR_INDEX);
21 | }
22 | }
23 |
24 | enum abstract UnusedLocalVarCheckTests(String) to String {
25 | var USED_INDEX = "
26 | abstractAndClass Test {
27 | function a() {
28 | var index:Int;
29 | index++;
30 | }
31 | @SuppressWarnings('checkstyle:UnusedLocalVar')
32 | function b() {
33 | var index:Int;
34 | }
35 |
36 | function c() {
37 | var index:Int;
38 | call(function() {
39 | index++;
40 | });
41 | }
42 | }";
43 | var UNUSED_INDEX = "
44 | abstractAndClass Test {
45 | // index
46 | @index
47 | public function a(index:String) {
48 | var index:Int;
49 | }
50 | }";
51 | var UNUSED_INDEX2 = "
52 | abstractAndClass Test {
53 | public function a() {
54 | call(function() {
55 | var index:Int;
56 | });
57 | }
58 | }";
59 | var STRING_INTERPOLATION = "
60 | abstractAndClass Test {
61 | function a() {
62 | var index:Int;
63 | var index2:Array;
64 | var index3:String;
65 | var index4:String;
66 |
67 | trace ('$index');
68 | trace ('${index2.toString()}');
69 | trace ('${Std.parseInt(index3)}');
70 | trace ('${index4}');
71 | }
72 | }";
73 | var STRING_INTERPOLATION_UNUSED = "
74 | abstractAndClass Test {
75 | function a() {
76 | var index:Int;
77 |
78 | trace ('index');
79 | trace ('$index2');
80 | trace ('${index2.toString()}');
81 | trace ('${Std.parseInt(index3)}');
82 | trace ('${index4}');
83 | }
84 | }";
85 | var MACRO = "
86 | abstractAndClass Test {
87 | function a() {
88 | var index:Int;
89 | var index2:Array;
90 | var index3:String;
91 | var index4:String;
92 |
93 | $index = 1;
94 | $v{index2};
95 | $i{index3};
96 | $a{index4};
97 | }
98 | }";
99 | var MACRO_UNUSED = "
100 | abstractAndClass Test {
101 | function a() {
102 | var index:Int;
103 |
104 | $v{index2};
105 | $i{index3};
106 | $a{index4};
107 | }
108 | }";
109 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/coding/VariableInitialisationCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.coding;
2 |
3 | class VariableInitialisationCheckTest extends CheckTestCase {
4 | @Test
5 | public function testVar() {
6 | assertMsg(new VariableInitialisationCheck(), TEST1, 'Invalid variable initialisation for "_a" (move initialisation to constructor or function)');
7 | }
8 |
9 | @Test
10 | public function testStatic() {
11 | assertNoMsg(new VariableInitialisationCheck(), TEST2);
12 | }
13 |
14 | @Test
15 | public function testEnumAbstract() {
16 | assertNoMsg(new VariableInitialisationCheck(), TEST3);
17 | }
18 |
19 | @Test
20 | public function testFinal() {
21 | var check:VariableInitialisationCheck = new VariableInitialisationCheck();
22 | assertMsg(check, FINAL, 'Invalid variable initialisation for "VALUE" (move initialisation to constructor or function)');
23 | assertNoMsg(check, FINAL_CONSTRUCTOR);
24 | check.allowFinal = true;
25 | assertNoMsg(check, FINAL);
26 | assertNoMsg(check, FINAL_CONSTRUCTOR);
27 | }
28 | }
29 |
30 | enum abstract VariableInitialisationCheckTests(String) to String {
31 | var TEST1 = "
32 | abstractAndClass Test {
33 | var _a:Int = 1;
34 |
35 | @SuppressWarnings('checkstyle:VariableInitialisation')
36 | var _b:Int = 1;
37 |
38 | public function new() {}
39 | }";
40 | var TEST2 = "
41 | abstractAndClass Test {
42 | static inline var TEST:Int = 1;
43 | inline var TEST2:Int = 1;
44 |
45 | public function new() {}
46 | }";
47 | var TEST3 = "
48 | enum
49 | abstract Test(Int) {
50 | var VALUE = 0;
51 | }";
52 | var FINAL = "
53 | abstractAndClass Test {
54 | final VALUE = 0;
55 | }";
56 | var FINAL_CONSTRUCTOR = "
57 | abstractAndClass Test {
58 | final VALUE;
59 |
60 | public function new() {
61 | VALUE = 1;
62 | }
63 | }";
64 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/comments/CommentedOutCodeCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.comments;
2 |
3 | class CommentedOutCodeCheckTest extends CheckTestCase {
4 | static inline var MSG_REMOVE_COMMENTED_CODE:String = "This block of commented-out lines of code should be removed";
5 |
6 | @Test
7 | public function testComments() {
8 | var check = new CommentedOutCodeCheck();
9 | assertMsg(check, BLOCK_COMMENT_VAR, MSG_REMOVE_COMMENTED_CODE);
10 | assertMsg(check, BLOCK_COMMENT_STAR_VAR, MSG_REMOVE_COMMENTED_CODE);
11 | assertMsg(check, BLOCK_COMMENT_MULTI_STAR_VAR, MSG_REMOVE_COMMENTED_CODE);
12 | assertMsg(check, LINE_COMMENT_VAR, MSG_REMOVE_COMMENTED_CODE);
13 | assertMsg(check, LINE_COMMENT_VAR2, MSG_REMOVE_COMMENTED_CODE);
14 | assertMsg(check, LINE_COMMENT_SWITCH, MSG_REMOVE_COMMENTED_CODE);
15 | assertMsg(check, LINE_COMMENT_SWITCH2, MSG_REMOVE_COMMENTED_CODE);
16 | assertNoMsg(check, LINE_COMMENT_EMPTY);
17 | assertNoMsg(check, LINE_COMMENT_SUPRESSED);
18 | // xx assertMessages(check, ONE_STAR_ONE_STAR_ONE_STAR, [MSG_SHOULD_USE_TWO_STARS, MSG_SHOULD_NOT_START_WITH_STAR]);
19 | }
20 | }
21 |
22 | enum abstract CommentedOutCodeCheckTests(String) to String {
23 | var BLOCK_COMMENT_VAR = "
24 | /*
25 | var test:String = '';
26 | */
27 | class Test {}
28 | ";
29 | var BLOCK_COMMENT_STAR_VAR = "
30 | /**
31 | var test:String = '';
32 | **/
33 | class Test {}
34 | ";
35 | var BLOCK_COMMENT_MULTI_STAR_VAR = "
36 | /**********************************************
37 | var test:String = '';
38 | **********************************************/
39 | class Test {}
40 | ";
41 | var LINE_COMMENT_VAR = "
42 | // var test:String = '';
43 | class Test {}
44 | ";
45 | var LINE_COMMENT_VAR2 = "
46 | // var test:String = '';
47 | // var test2:String = '';
48 | // var test3:String = '';
49 | class Test {}
50 | ";
51 | var LINE_COMMENT_SWITCH = "
52 | // switch(test) {
53 | // case ValueA:
54 | // var a = '';
55 | // call(a);
56 | // case ValueB:
57 | // case ValueC:
58 | // default:
59 | // }
60 | class Test {}
61 | ";
62 | var LINE_COMMENT_SWITCH2 = "
63 | // text comment
64 | // switch(test) {
65 | // case ValueA:
66 | // var a = '';
67 | // call(a);
68 | // case ValueB:
69 | // case ValueC:
70 | // default:
71 | // }
72 | class Test {}
73 | ";
74 | var LINE_COMMENT_EMPTY = "
75 | // text comment
76 | //
77 | /* */
78 | class Test {}
79 | ";
80 | var LINE_COMMENT_SUPRESSED = "
81 | @SuppressWarnings('checkstyle:CommentedOutCode')
82 | class Test {
83 | // var test:String = '';
84 | }
85 | ";
86 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/comments/DocCommentStyleCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.comments;
2 |
3 | class DocCommentStyleCheckTest extends CheckTestCase {
4 | static inline var MSG_SHOULD_USE_ONE_STAR:String = "Comment should use '/*…*/'";
5 | static inline var MSG_SHOULD_USE_TWO_STARS:String = "Comment should use '/**…**/'";
6 | static inline var MSG_SHOULD_NOT_START_WITH_STAR:String = "Comment lines should not start with '*'";
7 |
8 | @Test
9 | public function testDefault() {
10 | var check = new DocCommentStyleCheck();
11 |
12 | assertNoMsg(check, TWO_STAR_NO_STAR_TWO_STAR);
13 | assertNoMsg(check, MANY_STARS_NO_STAR_MANY_STARS);
14 | assertMsg(check, ONE_STAR_NO_STAR_ONE_STAR, MSG_SHOULD_USE_TWO_STARS);
15 | assertMessages(check, ONE_STAR_ONE_STAR_ONE_STAR, [MSG_SHOULD_USE_TWO_STARS, MSG_SHOULD_NOT_START_WITH_STAR]);
16 | assertMsg(check, TWO_STAR_ONE_STAR_TWO_STAR, MSG_SHOULD_NOT_START_WITH_STAR);
17 | assertMsg(check, TWO_STAR_TWO_STARS_TWO_STAR, MSG_SHOULD_NOT_START_WITH_STAR);
18 | }
19 |
20 | @Test
21 | public function testOneStarStart() {
22 | var check = new DocCommentStyleCheck();
23 | check.startStyle = ONE_STAR;
24 | check.lineStyle = IGNORE;
25 |
26 | assertNoMsg(check, ONE_STAR_NO_STAR_ONE_STAR);
27 | assertNoMsg(check, ONE_STAR_ONE_STAR_ONE_STAR);
28 | assertMsg(check, TWO_STAR_NO_STAR_TWO_STAR, MSG_SHOULD_USE_ONE_STAR);
29 | assertMsg(check, MANY_STARS_NO_STAR_MANY_STARS, MSG_SHOULD_USE_ONE_STAR);
30 | assertMsg(check, TWO_STAR_ONE_STAR_TWO_STAR, MSG_SHOULD_USE_ONE_STAR);
31 | assertMsg(check, TWO_STAR_TWO_STARS_TWO_STAR, MSG_SHOULD_USE_ONE_STAR);
32 | }
33 |
34 | @Test
35 | public function testTwoStarStart() {
36 | var check = new DocCommentStyleCheck();
37 | check.startStyle = TWO_STARS;
38 | check.lineStyle = IGNORE;
39 |
40 | assertMsg(check, ONE_STAR_NO_STAR_ONE_STAR, MSG_SHOULD_USE_TWO_STARS);
41 | assertMsg(check, ONE_STAR_ONE_STAR_ONE_STAR, MSG_SHOULD_USE_TWO_STARS);
42 | assertNoMsg(check, TWO_STAR_NO_STAR_TWO_STAR);
43 | assertNoMsg(check, MANY_STARS_NO_STAR_MANY_STARS);
44 | assertNoMsg(check, TWO_STAR_ONE_STAR_TWO_STAR);
45 | assertNoMsg(check, TWO_STAR_TWO_STARS_TWO_STAR);
46 | }
47 | }
48 |
49 | enum abstract DocCommentStyleCheckTests(String) to String {
50 | var TWO_STAR_NO_STAR_TWO_STAR = "
51 | /**
52 | comment
53 | **/
54 | class Test {}
55 | ";
56 | var ONE_STAR_NO_STAR_ONE_STAR = "
57 | /*
58 | comment
59 | */
60 | class Test {}
61 | ";
62 | var ONE_STAR_ONE_STAR_ONE_STAR = "
63 | /*
64 | * comment
65 | */
66 | class Test {}
67 | ";
68 | var TWO_STAR_ONE_STAR_TWO_STAR = "
69 | /**
70 | * comment
71 | **/
72 | class Test {}
73 | ";
74 | var TWO_STAR_TWO_STARS_TWO_STAR = "
75 | /**
76 | ** comment
77 | **/
78 | class Test {}
79 | ";
80 | var MANY_STARS_NO_STAR_MANY_STARS = "
81 | /******************
82 | comment
83 | ******************/
84 | class Test {}
85 | ";
86 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/comments/TODOCommentCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.comments;
2 |
3 | import checkstyle.SeverityLevel;
4 |
5 | class TODOCommentCheckTest extends CheckTestCase {
6 | @Test
7 | public function testTODO() {
8 | var check = new TODOCommentCheck();
9 | check.severity = SeverityLevel.INFO;
10 | assertMsg(check, TEST1, "TODO comment: TODO: remove test");
11 | }
12 |
13 | @Test
14 | public function testFIXME() {
15 | var check = new TODOCommentCheck();
16 | check.severity = SeverityLevel.INFO;
17 | assertMsg(check, TEST2, "TODO comment: FIXME remove test");
18 | }
19 |
20 | @Test
21 | public function testHACK() {
22 | var check = new TODOCommentCheck();
23 | check.severity = SeverityLevel.INFO;
24 | assertMsg(check, TEST3, "TODO comment: HACK remove test");
25 | }
26 |
27 | @Test
28 | public function testBUG() {
29 | var check = new TODOCommentCheck();
30 | check.severity = SeverityLevel.INFO;
31 | assertMsg(check, TEST4, "TODO comment: BUG #171: remove test");
32 | }
33 |
34 | @Test
35 | public function testXXX() {
36 | var check = new TODOCommentCheck();
37 | check.severity = SeverityLevel.INFO;
38 | assertMsg(check, TEST5, "TODO comment: XXX remove test");
39 | }
40 |
41 | @Test
42 | public function testString() {
43 | var check = new TODOCommentCheck();
44 | check.severity = SeverityLevel.INFO;
45 | assertNoMsg(check, TEST6);
46 | }
47 |
48 | @Test
49 | public function testInsideComment() {
50 | var check = new TODOCommentCheck();
51 | check.severity = SeverityLevel.INFO;
52 | assertNoMsg(check, TEST7);
53 | }
54 | }
55 |
56 | enum abstract TODOCommentCheckTests(String) to String {
57 | var TEST1 = "
58 | class Test {
59 | // TODO: remove test
60 | public override function test() {}
61 | }";
62 | var TEST2 = "
63 | class Test {
64 | // FIXME remove test
65 | public override function test() {}
66 | }";
67 | var TEST3 = "
68 | class Test {
69 | // HACK remove test
70 | public override function test() {}
71 | }";
72 | var TEST4 = "
73 | class Test {
74 | // BUG #171: remove test
75 | public override function test() {}
76 | }";
77 | var TEST5 = "
78 | class Test {
79 | // XXX remove test
80 | public override function test() {}
81 | }";
82 | var TEST6 = "
83 | class Test {
84 | var a:String = 'TODO: remove test';
85 | public override function test() {}
86 | }";
87 | var TEST7 = "
88 | class Test {
89 | function test() {
90 | //trace('TODO');
91 | //trace('FIXME');
92 | //trace('BUG:');
93 | //Test TODO:;
94 | }
95 | }";
96 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/design/EmptyPackageCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.design;
2 |
3 | class EmptyPackageCheckTest extends CheckTestCase {
4 | @Test
5 | public function testEmptyPackage() {
6 | assertMsg(new EmptyPackageCheck(), TEST1, "Found empty package");
7 | assertNoMsg(new EmptyPackageCheck(), TEST3);
8 | }
9 |
10 | @Test
11 | public function testCorrectPackage() {
12 | assertNoMsg(new EmptyPackageCheck(), TEST2);
13 | }
14 |
15 | @Test
16 | public function testEnforceEmptyPackage() {
17 | var check = new EmptyPackageCheck();
18 | check.enforceEmptyPackage = true;
19 |
20 | assertNoMsg(check, TEST1);
21 | assertNoMsg(check, TEST2);
22 | assertMsg(check, TEST3, "Missing package declaration");
23 | }
24 | }
25 |
26 | enum abstract EmptyPackageCheckTests(String) to String {
27 | var TEST1 = "
28 | package;
29 |
30 | class Test {
31 | public function new() {}
32 | }";
33 | var TEST2 = "
34 | package checks.test;
35 |
36 | class Test {
37 | public function new() {}
38 | }";
39 | var TEST3 = "
40 | class Test {
41 | public function new() {}
42 | }";
43 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/design/InterfaceCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.design;
2 |
3 | class InterfaceCheckTest extends CheckTestCase {
4 | static inline var PROPERTIES_MSG:String = "Properties are not allowed in interfaces";
5 | static inline var MARKER_MSG:String = "Marker interfaces are not allowed";
6 |
7 | @Test
8 | public function testWithJustProperties() {
9 | assertMsg(new InterfaceCheck(), TEST1, PROPERTIES_MSG);
10 | }
11 |
12 | @Test
13 | public function testMarkerInterface() {
14 | assertNoMsg(new InterfaceCheck(), TEST2);
15 | }
16 |
17 | @Test
18 | public function testNoMarkerInterface() {
19 | var check = new InterfaceCheck();
20 | check.allowMarkerInterfaces = false;
21 | assertMsg(check, TEST2, MARKER_MSG);
22 | }
23 |
24 | @Test
25 | public function testCorrectInterface() {
26 | assertNoMsg(new InterfaceCheck(), TEST3);
27 | }
28 |
29 | @Test
30 | public function testAllowProperties() {
31 | var check = new InterfaceCheck();
32 | check.allowProperties = true;
33 | assertNoMsg(check, TEST4);
34 | }
35 | }
36 |
37 | enum abstract InterfaceCheckTests(String) to String {
38 | var TEST1 = "
39 | interface IComponentController {
40 | var a:Int = 1;
41 | }";
42 | var TEST2 = "
43 | interface IComponentController {}";
44 | var TEST3 = "
45 | interface IComponentController {
46 | function init():Void;
47 | }";
48 | var TEST4 = "
49 | interface IComponentController {
50 | var a:Int;
51 | var b:String;
52 | function init():Void;
53 | }";
54 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/imports/AvoidStarImportCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.imports;
2 |
3 | class AvoidStarImportCheckTest extends CheckTestCase {
4 | static inline var MSG_STAR_IMPORT:String = 'Using the ".*" form of import should be avoided';
5 |
6 | @Test
7 | public function testNoStarImport() {
8 | var check = new AvoidStarImportCheck();
9 | assertNoMsg(check, IMPORT);
10 | }
11 |
12 | @Test
13 | public function testStarImport() {
14 | var check = new AvoidStarImportCheck();
15 | assertMsg(check, STAR_IMPORT, MSG_STAR_IMPORT);
16 | assertMsg(check, CONDITIONAL_STAR_IMPORT_ISSUE_160, MSG_STAR_IMPORT);
17 | assertMsg(check, CONDITIONAL_ELSE_STAR_IMPORT, MSG_STAR_IMPORT);
18 | assertMessages(check, CONDITIONAL_ELSEIF_STAR_IMPORT, [MSG_STAR_IMPORT, MSG_STAR_IMPORT, MSG_STAR_IMPORT]);
19 | }
20 | }
21 |
22 | enum abstract AvoidStarImportCheckTests(String) to String {
23 | var IMPORT = "
24 | package haxe.checkstyle;
25 |
26 | import haxe.checkstyle.Check;
27 | import haxe.checkstyle.Check2;
28 | import haxe.checkstyle.Check3;
29 |
30 | using haxe.checkstyle.Check;
31 |
32 | class Test {
33 | public function new() {}
34 | }";
35 | var STAR_IMPORT = "
36 | package haxe.checkstyle;
37 |
38 | import haxe.checkstyle.*;
39 | import haxe.checkstyle.Check2;
40 | import haxe.checkstyle.Check3;
41 |
42 | using haxe.checkstyle.Check;
43 |
44 | class Test {
45 | public function new() {}
46 | }";
47 | var CONDITIONAL_STAR_IMPORT_ISSUE_160 = "
48 | #if macro
49 | import haxe.macro.*;
50 | #end";
51 | var CONDITIONAL_ELSEIF_STAR_IMPORT = "
52 | #if macro
53 | import haxe.macro.Type;
54 | #elseif neko
55 | import haxe.macro.*;
56 | #elseif neko
57 | import haxe.macro.*;
58 | #else
59 | #if linux
60 | import haxe.macro.Type;
61 | #else
62 | import haxe.macro.*;
63 | #end
64 | #end
65 | import haxe.macro.Type;";
66 | var CONDITIONAL_ELSE_STAR_IMPORT = "
67 | #if macro
68 | import haxe.macro.Type;
69 | #else
70 | import haxe.macro.*;
71 | #end
72 | import haxe.macro.Type;";
73 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/literal/ArrayLiteralCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.literal;
2 |
3 | class ArrayLiteralCheckTest extends CheckTestCase {
4 | @Test
5 | public function testWrongArrayInstantiation() {
6 | assertMsg(new ArrayLiteralCheck(), TEST1, 'Bad array instantiation, use the array literal notation "[]" which is shorter and cleaner');
7 | }
8 |
9 | @Test
10 | public function testCorrectArrayInstantiation() {
11 | assertNoMsg(new ArrayLiteralCheck(), TEST2);
12 | }
13 | }
14 |
15 | enum abstract ArrayLiteralCheckTests(String) to String {
16 | var TEST1 = "
17 | abstractAndClass Test {
18 | var _arr:Array = new Array();
19 | }";
20 | var TEST2 = "
21 | abstractAndClass Test {
22 | var _arr:Array = [];
23 | }";
24 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/literal/ERegLiteralCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.literal;
2 |
3 | class ERegLiteralCheckTest extends CheckTestCase {
4 | @Test
5 | public function testCorrectEReg() {
6 | assertNoMsg(new ERegLiteralCheck(), TEST2);
7 | }
8 |
9 | @Test
10 | public function testWrongEReg() {
11 | assertMsg(new ERegLiteralCheck(), TEST1, 'Bad EReg instantiation, define expression between "~/" and "/"');
12 | }
13 |
14 | @Test
15 | public function testIssue43() {
16 | assertNoMsg(new ERegLiteralCheck(), ISSUE_43);
17 | }
18 |
19 | @Test
20 | public function testIssue99() {
21 | assertNoMsg(new ERegLiteralCheck(), REGEX_WITH_STRING_INTERPOLATION);
22 | }
23 | }
24 |
25 | enum abstract ERegLiteralCheckTests(String) to String {
26 | var TEST1 = "
27 | abstractAndClass Test {
28 | var _reg:EReg = new EReg('test', 'i');
29 | }";
30 | var TEST2 = "
31 | abstractAndClass Test {
32 | var _reg:EReg = ~/test/i;
33 | }";
34 | var ISSUE_43 = "
35 | abstractAndClass Test {
36 | function test() {
37 | cast (Type.createInstance(Array, []));
38 | }
39 | }";
40 | var REGEX_WITH_STRING_INTERPOLATION = "
41 | abstractAndClass Test {
42 | var regex = new EReg('^${pattern}$', 'ig');
43 | }";
44 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/literal/HexadecimalLiteralCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.literal;
2 |
3 | class HexadecimalLiteralCheckTest extends CheckTestCase {
4 | @Test
5 | public function test1() {
6 | assertMsg(new HexadecimalLiteralCheck(), TEST1, "Bad hexadecimal literal, use upperCase");
7 | }
8 |
9 | @Test
10 | public function test2() {
11 | assertNoMsg(new HexadecimalLiteralCheck(), TEST2);
12 | }
13 |
14 | @Test
15 | public function test3() {
16 | var check = new HexadecimalLiteralCheck();
17 | check.option = LOWER_CASE;
18 | assertMsg(check, TEST3, "Bad hexadecimal literal, use lowerCase");
19 | }
20 | }
21 |
22 | enum abstract HexadecimalLiteralCheckTests(String) to String {
23 | var TEST1 = "
24 | abstractAndClass Test {
25 | var clr = 0xffffff;
26 | }";
27 | var TEST2 = "
28 | abstractAndClass Test {
29 | var clr = 0x0033FF;
30 | }";
31 | var TEST3 = "
32 | abstractAndClass Test {
33 | var clr = 0x0033FF;
34 | }";
35 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/meta/RedundantAccessMetaCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.meta;
2 |
3 | class RedundantAccessMetaCheckTest extends CheckTestCase {
4 | @Test
5 | public function testRedundantAccess() {
6 | var check = new RedundantAccessMetaCheck();
7 | assertNoMsg(check, CORRECT_ACCESS);
8 | assertMsg(check, REDUNDANT_ACCESS, 'Redundant "@:access(pack.age.Test)" for field "test" detected');
9 | assertMsg(check, REDUNDANT_ACCESS_PACKAGE, 'Redundant "@:access(pack.age.Test)" for field "test" detected');
10 | }
11 |
12 | @Test
13 | public function testProhibitMeta() {
14 | var check = new RedundantAccessMetaCheck();
15 | check.prohibitMeta = true;
16 | assertMessages(check, CORRECT_ACCESS, [
17 | 'Consider removing "@:access(pack.age.Test)"',
18 | 'Consider removing "@:access(pack.age.Test2)"',
19 | 'Consider removing "@:access(pack.age.Test2)"'
20 | ]);
21 | assertMessages(check, REDUNDANT_ACCESS, [
22 | 'Consider removing "@:access(pack.age.Test)"',
23 | 'Consider removing "@:access(pack.age.Test)"'
24 | ]);
25 | assertMessages(check, REDUNDANT_ACCESS_PACKAGE, [
26 | 'Consider removing "@:access(pack.age)"',
27 | 'Consider removing "@:access(pack.age.Test)"'
28 | ]);
29 |
30 | check.prohibitMeta = false;
31 | assertNoMsg(check, CORRECT_ACCESS);
32 | assertMsg(check, REDUNDANT_ACCESS, 'Redundant "@:access(pack.age.Test)" for field "test" detected');
33 | assertMsg(check, REDUNDANT_ACCESS_PACKAGE, 'Redundant "@:access(pack.age.Test)" for field "test" detected');
34 | }
35 | }
36 |
37 | enum abstract RedundantAccessMetaCheckTests(String) to String {
38 | var CORRECT_ACCESS = "
39 | @:access(pack.age.Test)
40 | abstractAndClass Test {
41 |
42 | @:access(pack.age.Test2)
43 | function test() {}
44 | }
45 |
46 | abstractAndClass Test2 {
47 |
48 | @:access(pack.age.Test2)
49 | function test() {}
50 | }";
51 | var REDUNDANT_ACCESS = "
52 | @:access(pack.age.Test)
53 | abstractAndClass Test {
54 |
55 | @:access(pack.age.Test)
56 | function test() {}
57 | }";
58 | var REDUNDANT_ACCESS_PACKAGE = "
59 | @:access(pack.age)
60 | abstractAndClass Test {
61 |
62 | @:access(pack.age.Test)
63 | function test() {}
64 | }";
65 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/meta/RedundantAllowMetaCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.meta;
2 |
3 | class RedundantAllowMetaCheckTest extends CheckTestCase {
4 | @Test
5 | public function testRedundantAccess() {
6 | var check = new RedundantAllowMetaCheck();
7 | assertNoMsg(check, CORRECT_ACCESS);
8 | assertMsg(check, REDUNDANT_ACCESS, 'Redundant "@:allow(pack.age.Test)" for field "test" detected');
9 | assertMsg(check, REDUNDANT_ACCESS_PACKAGE, 'Redundant "@:allow(pack.age.Test)" for field "test" detected');
10 | assertMsg(check, REDUNDANT_ACCESS_PUBLIC, 'Redundant "@:allow(pack.age.Test)" for public field "test" detected');
11 | }
12 |
13 | @Test
14 | public function testProhibitMeta() {
15 | var check = new RedundantAllowMetaCheck();
16 | check.prohibitMeta = true;
17 | assertMessages(check, CORRECT_ACCESS, [
18 | 'Consider removing "@:allow(pack.age.Test)"',
19 | 'Consider removing "@:allow(pack.age.Test2)"'
20 | ]);
21 | assertMessages(check, REDUNDANT_ACCESS, [
22 | 'Consider removing "@:allow(pack.age.Test)"',
23 | 'Consider removing "@:allow(pack.age.Test)"'
24 | ]);
25 | assertMessages(check, REDUNDANT_ACCESS_PACKAGE, [
26 | 'Consider removing "@:allow(pack.age)"',
27 | 'Consider removing "@:allow(pack.age.Test)"'
28 | ]);
29 | assertMsg(check, REDUNDANT_ACCESS_PUBLIC, 'Consider removing "@:allow(pack.age.Test)"');
30 |
31 | check.prohibitMeta = false;
32 | assertNoMsg(check, CORRECT_ACCESS);
33 | assertMsg(check, REDUNDANT_ACCESS, 'Redundant "@:allow(pack.age.Test)" for field "test" detected');
34 | assertMsg(check, REDUNDANT_ACCESS_PACKAGE, 'Redundant "@:allow(pack.age.Test)" for field "test" detected');
35 | assertMsg(check, REDUNDANT_ACCESS_PUBLIC, 'Redundant "@:allow(pack.age.Test)" for public field "test" detected');
36 | }
37 | }
38 |
39 | enum abstract RedundantAllowMetaCheckTests(String) to String {
40 | var CORRECT_ACCESS = "
41 | @:allow(pack.age.Test)
42 | abstractAndClass Test {
43 |
44 | @:allow(pack.age.Test2)
45 | function test() {}
46 | }
47 |
48 | abstractAndClass Test2 {
49 |
50 | @:access(pack.age.Test2)
51 | function test() {}
52 | }";
53 | var REDUNDANT_ACCESS = "
54 | @:allow(pack.age.Test)
55 | abstractAndClass Test {
56 |
57 | @:allow(pack.age.Test)
58 | function test() {}
59 | }";
60 | var REDUNDANT_ACCESS_PACKAGE = "
61 | @:allow(pack.age)
62 | abstractAndClass Test {
63 |
64 | @:allow(pack.age.Test)
65 | function test() {}
66 | }";
67 | var REDUNDANT_ACCESS_PUBLIC = "
68 | abstractAndClass Test {
69 |
70 | @:allow(pack.age.Test)
71 | public function test() {}
72 | }";
73 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/metrics/CyclomaticComplexityCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.metrics;
2 |
3 | class CyclomaticComplexityCheckTest extends CheckTestCase {
4 | @Test
5 | public function testCorrectNaming() {
6 | var check = new CyclomaticComplexityCheck();
7 | check.thresholds = [{severity: "WARNING", complexity: 1}, {severity: "ERROR", complexity: 2}];
8 | assertMsg(check, TEST, 'Method "test" is too complex (score: 2).');
9 |
10 | check.thresholds = [{severity: "IGNORE", complexity: 1}, {severity: "IGNORE", complexity: 2}];
11 | assertNoMsg(check, TEST);
12 | }
13 | }
14 |
15 | enum abstract CyclomaticComplexityCheckTests(String) to String {
16 | var TEST = "
17 | class Test {
18 | function test() {
19 | var a:Array = [0, 5, 20];
20 | for (i in 0 ... a.length) {
21 | var b = Browser.document.createOptionElement();
22 | option.value = i;
23 | option.innerText = i;
24 | }
25 | }
26 | }";
27 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/modifier/FinalCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.modifier;
2 |
3 | class FinalCheckTest extends CheckTestCase {
4 | static inline var ERROR_INLINE_VAR:String = 'Consider using "inline final" for field "test"';
5 | static inline var ERROR_PUBLIC_STATIC:String = 'Consider making public static field "test" "final" or "private"';
6 |
7 | @Test
8 | public function testInlineFinal() {
9 | var check = new FinalCheck();
10 | assertNoMsg(check, TEST_INLINE_FINAL);
11 | }
12 |
13 | @Test
14 | public function testNoncompliant() {
15 | var check = new FinalCheck();
16 | assertMsg(check, TEST_INLINE_VAR, ERROR_INLINE_VAR);
17 | assertMsg(check, TEST_PUBLIC_STATIC_VAR, ERROR_PUBLIC_STATIC);
18 | }
19 | }
20 |
21 | enum abstract FinalCheckTests(String) to String {
22 | var TEST_INLINE_FINAL = "
23 | abstractAndClass Test {
24 | public inline final test:String = '0';
25 | public static final test2:String = '0';
26 | public static var test3(default, null):String = '0';
27 | private static var test4:String = '0';
28 | public var test5:String = '0';
29 | private var test5:String = '0';
30 | final function test2() {
31 | }
32 | }";
33 | var TEST_INLINE_VAR = "
34 | abstractAndClass Test {
35 | inline public var test:String = '0';
36 | inline function test2() {
37 | }
38 | }";
39 | var TEST_PUBLIC_STATIC_VAR = "
40 | abstractAndClass Test {
41 | public static var test:String = '0';
42 | public static function test2() {
43 | }
44 | }";
45 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/modifier/PublicAccessorCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.modifier;
2 |
3 | class PublicAccessorCheckTest extends CheckTestCase {
4 | static inline var ERROR:String = "Accessor method should not be public";
5 |
6 | @Test
7 | public function testNonAccessors() {
8 | assertNoMsg(new PublicAccessorCheck(), NON_ACCESSOR);
9 | assertNoMsg(new PublicAccessorCheck(), PRIVATE_ACCESSOR);
10 | }
11 |
12 | @Test
13 | public function testPublicAccessors() {
14 | assertMsg(new PublicAccessorCheck(), PUBLIC_GETTER, ERROR);
15 | assertMsg(new PublicAccessorCheck(), PUBLIC_SETTER, ERROR);
16 | assertMsg(new PublicAccessorCheck(), IMPLICITLY_PUBLIC_GETTER, ERROR);
17 | assertMsg(new PublicAccessorCheck(), IMPLICITLY_PUBLIC_SETTER, ERROR);
18 | assertMsg(new PublicAccessorCheck(), INTERFACE_PUBLIC_GETTER, ERROR);
19 | assertMsg(new PublicAccessorCheck(), INTERFACE_PUBLIC_SETTER, ERROR);
20 | }
21 | }
22 |
23 | enum abstract PublicAccessorCheckTests(String) to String {
24 | var NON_ACCESSOR = "
25 | abstractAndClass Test {
26 | public function _set_test() {}
27 | public function _get_test() {}
28 | }";
29 | var PRIVATE_ACCESSOR = "
30 | abstractAndClass Test {
31 | private function set_test() {}
32 | private function get_test() {}
33 | }";
34 | var PUBLIC_GETTER = "
35 | abstractAndClass Test {
36 | public function get_test() {}
37 | }";
38 | var PUBLIC_SETTER = "
39 | abstractAndClass Test {
40 | override inline public function set_test() {}
41 | }";
42 | var IMPLICITLY_PUBLIC_GETTER = "
43 | @:publicFields class Test {
44 | function get_test() {}
45 | }";
46 | var IMPLICITLY_PUBLIC_SETTER = "
47 | @:publicFields class Test {
48 | function set_test() {}
49 | }";
50 | var INTERFACE_PUBLIC_GETTER = "
51 | interface ITest {
52 | function get_test() {}
53 | }";
54 | var INTERFACE_PUBLIC_SETTER = "
55 | interface ITest {
56 | function set_test() {}
57 | }";
58 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/naming/CatchParameterNameCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.naming;
2 |
3 | class CatchParameterNameCheckTest extends CheckTestCase {
4 | @Test
5 | public function testCorrectNaming() {
6 | var check = new CatchParameterNameCheck();
7 | assertNoMsg(check, TEST1);
8 | }
9 |
10 | @Test
11 | public function testInCorrectNaming() {
12 | var check = new CatchParameterNameCheck();
13 | assertMsg(check, TEST2, '"Val" must match pattern "~/${check.format}/"');
14 | }
15 |
16 | @Test
17 | public function testCustomNaming() {
18 | var check = new CatchParameterNameCheck();
19 | check.format = "^(ex)$";
20 | assertMsg(check, TEST1, '"e" must match pattern "~/${check.format}/"');
21 | }
22 | }
23 |
24 | enum abstract CatchParameterNameCheckTests(String) to String {
25 | var TEST1 = "
26 | class Test {
27 | public function test() {
28 | try {
29 | var Count:Int = 1;
30 | }
31 | catch(e:String) {}
32 | }
33 | }";
34 | var TEST2 = "
35 | class Test {
36 | public function test() {
37 | try {
38 | var Count:Int = 1;
39 | }
40 | catch(Val:String) {}
41 | }
42 | }";
43 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/naming/FileNameCaseCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.naming;
2 |
3 | class FileNameCaseCheckTest extends CheckTestCase {
4 | @Test
5 | public function testCorrectNaming() {
6 | var check = new FileNameCaseCheck();
7 | assertNoMsg(check, IMPORT, "import.hx");
8 | assertNoMsg(check, TYPES, "Test.hx");
9 | assertNoMsg(check, TYPES, "ITest.hx");
10 | assertNoMsg(check, TYPES, "Test2.hx");
11 | assertNoMsg(check, TYPES, "Test3.hx");
12 | }
13 |
14 | @Test
15 | public function testIncorrectImport() {
16 | var check = new FileNameCaseCheck();
17 | assertMsg(check, IMPORT, '"Import.hx" contains no types - consider renaming to "import.hx"', "Import.hx");
18 | assertMsg(check, TYPES, '"import.hx" contains types', "import.hx");
19 | }
20 |
21 | @Test
22 | public function testModuleWithNoTypes() {
23 | var check = new FileNameCaseCheck();
24 | assertMsg(check, IMPORT, '"Main.hx" defines no type with name "Main"', "Main.hx");
25 | }
26 |
27 | @Test
28 | public function testIncorrectCase() {
29 | var check = new FileNameCaseCheck();
30 |
31 | assertMessages(check, TYPES, [
32 | '"TeSt.hx" defines type "Test" using different case',
33 | '"TeSt.hx" defines no type with name "TeSt"'
34 | ], "TeSt.hx");
35 |
36 | assertMessages(check, TYPES, [
37 | '"Itest.hx" defines type "ITest" using different case',
38 | '"Itest.hx" defines no type with name "Itest"'
39 | ], "Itest.hx");
40 | }
41 | }
42 |
43 | enum abstract FileNameCaseCheckTests(String) to String {
44 | var IMPORT = "
45 | import haxe.io.Path;
46 | import checkstyle.checks.Check;
47 |
48 | using StringTools;
49 | ";
50 |
51 | var TYPES = "
52 | class Test {
53 | public var a:Int;
54 | private var b:Int;
55 | static var COUNT:Int = 1;
56 | static inline var COUNT2:Int = 1;
57 | var count5:Int = 1;
58 | }
59 |
60 | interface ITest {
61 |
62 | }
63 |
64 | enum Test2 {
65 | count;
66 | a;
67 | }
68 |
69 | typedef Test3 = {
70 | var count1:Int;
71 | var count2:String;
72 | }";
73 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/naming/ListenerNameCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.naming;
2 |
3 | class ListenerNameCheckTest extends CheckTestCase {
4 | @Test
5 | public function testCorrectListenerName() {
6 | assertNoMsg(new ListenerNameCheck(), TEST);
7 | }
8 |
9 | @Test
10 | public function testListenerName1() {
11 | var check = new ListenerNameCheck();
12 | check.format = "^_?on.*";
13 | assertMsg(check, TEST1, 'Wrong listener name: "_testUpdate" (should be "~/${check.format}/")');
14 | }
15 | }
16 |
17 | enum abstract ListenerNameCheckTests(String) to String {
18 | var TEST = "
19 | abstractAndClass Test {
20 | var a:Stage;
21 | public function new() {
22 | a.addOnce('update', _onUpdate);
23 | }
24 |
25 | function _onUpdate() {}
26 | }";
27 | var TEST1 = "
28 | abstractAndClass Test {
29 | var a:Stage;
30 | public function new() {
31 | a.addEventListener('update', _testUpdate);
32 | }
33 |
34 | function _testUpdate() {}
35 | }";
36 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/naming/LocalVariableNameCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.naming;
2 |
3 | class LocalVariableNameCheckTest extends CheckTestCase {
4 | @Test
5 | public function testCorrectNaming() {
6 | var check = new LocalVariableNameCheck();
7 | assertNoMsg(check, TEST);
8 | assertNoMsg(check, TEST4);
9 | }
10 |
11 | @Test
12 | public function testWrongNaming() {
13 | var check = new LocalVariableNameCheck();
14 | var message = 'Invalid local var signature: "Count" (name should be "~/${check.format}/")';
15 | assertMsg(check, TEST1, message);
16 | assertMsg(check, TEST3, message);
17 | }
18 |
19 | @Test
20 | public function testIgnoreExtern() {
21 | var check = new LocalVariableNameCheck();
22 | check.ignoreExtern = false;
23 |
24 | assertNoMsg(check, TEST);
25 |
26 | var message = 'Invalid local var signature: "Count" (name should be "~/${check.format}/")';
27 | assertMsg(check, TEST1, message);
28 | assertMsg(check, TEST3, message);
29 | assertMsg(check, TEST4, message);
30 | }
31 |
32 | @Test
33 | public function testFormat() {
34 | var check = new LocalVariableNameCheck();
35 | check.format = "^[A-Za-z_]*$";
36 |
37 | assertMessages(check, TEST, [
38 | 'Invalid local var signature: "count1" (name should be "~/${check.format}/")',
39 | 'Invalid local var signature: "count2" (name should be "~/${check.format}/")'
40 | ]);
41 | assertNoMsg(check, TEST1);
42 | assertNoMsg(check, TEST3);
43 | assertNoMsg(check, TEST4);
44 | }
45 | }
46 |
47 | enum abstract LocalVariableNameCheckTests(String) to String {
48 | var TEST = "
49 | class Test {
50 | public function test() {
51 | var a:Int;
52 | var b:Int;
53 | }
54 | @SuppressWarnings('checkstyle:LocalVariableName')
55 | public function test() {
56 | var I:Int;
57 | }
58 | }
59 |
60 | enum Test2 {
61 | count;
62 | a;
63 | }
64 |
65 | typedef Test3 = {
66 | public function test() {
67 | var count1:Int;
68 | var count2:String;
69 | };
70 | @SuppressWarnings('checkstyle:LocalVariableName')
71 | var COUNT6:Int = 1;
72 | }
73 |
74 | typedef Test4 = {
75 | @SuppressWarnings('checkstyle:LocalVariableName')
76 | public function test() {
77 | var Count1:Int;
78 | };
79 | }";
80 | var TEST1 = "
81 | class Test {
82 | public function test() {
83 | var Count:Int = 1;
84 | }
85 | }";
86 | var TEST3 = "
87 | typedef Test = {
88 | public function test() {
89 | var Count:Int;
90 | }
91 | }";
92 | var TEST4 = "
93 | extern class Test {
94 | public function test() {
95 | var Count:Int = 1;
96 | }
97 | }";
98 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/size/LineLengthCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.size;
2 |
3 | class LineLengthCheckTest extends CheckTestCase {
4 | @Test
5 | public function testDefaultLineLength() {
6 | assertMsg(new LineLengthCheck(), TEST1, "Line is longer than 160 characters (found 178)");
7 | }
8 |
9 | @Test
10 | public function testCorrectLineLength() {
11 | assertNoMsg(new LineLengthCheck(), TEST2);
12 | }
13 |
14 | @Test
15 | public function testConfigurableLineLength() {
16 | var check = new LineLengthCheck();
17 | check.max = 40;
18 | assertMsg(check, TEST3, "Line is longer than 40 characters (found 73)");
19 | }
20 | }
21 |
22 | enum abstract LineLengthCheckTests(String) to String {
23 | var TEST1 = "
24 | class Test {
25 | var _a:Int;
26 | public function new() {
27 | var s = 'LONG LINE TEST LONG LINE TEST LONG LINE TEST LONG LINE TEST LONG LINE TEST LONG LINE TEST LONG LINE TEST LONG LINE TEST LONG LINE TEST LONG LINE TEST LONG LINE TEST';
28 | }
29 | }";
30 | var TEST2 = "
31 | class Test {
32 | public function new() {
33 | var b:Int;
34 | }
35 |
36 | @SuppressWarnings('checkstyle:LineLength')
37 | public function newi(param1:Int, param2:Int, param3:Int, param4:Int, param5:Int, param6:Int, param7:Int, param8:Int) {
38 | _a = 10;
39 | if (_a > 200 && _a < 250 && _a != 240 && _a != 250 && _a != 260 && _a != 270 && _a != 280 && _a != 290) {
40 | _a = -1;
41 | }
42 | }
43 | }";
44 | var TEST3 = "
45 | class Test {
46 | public function new() {
47 | var s = 'LONG LINE TEST LONG LINE TEST LONG LINE TEST LONG LINE TEST';
48 | }
49 | }";
50 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/type/AnonymousCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.type;
2 |
3 | class AnonymousCheckTest extends CheckTestCase {
4 | @Test
5 | public function testAnonymousStructureClassVar() {
6 | assertMsg(new AnonymousCheck(), TEST1, 'Anonymous structure "anonymous" found, use "typedef"');
7 | }
8 |
9 | @Test
10 | public function testAnonymousStructureLocalVar() {
11 | assertMsg(new AnonymousCheck(), TEST2, 'Anonymous structure "b" found, use "typedef"');
12 | }
13 | }
14 |
15 | enum abstract AnonymousCheckTests(String) to String {
16 | var TEST1 = "
17 | abstractAndClass Test {
18 | var anonymous:{a:Int, b:Int};
19 | }";
20 | var TEST2 = "
21 | abstractAndClass Test {
22 | public function new() {
23 | var b:{a:Int, b:Int};
24 | }
25 | }";
26 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/type/AvoidIdentifierCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.type;
2 |
3 | class AvoidIdentifierCheckTest extends CheckTestCase {
4 | @Test
5 | public function testCorrectTypeHints() {
6 | var check = new AvoidIdentifierCheck();
7 | assertNoMsg(check, TEST);
8 |
9 | check.avoidIdentifiers = ["TokenTree"];
10 | assertMsg(check, TEST, 'Identifier "TokenTree" should be avoided');
11 | check.avoidIdentifiers = ["a"];
12 | assertMsg(check, TEST, 'Identifier "a" should be avoided');
13 |
14 | check.avoidIdentifiers = ["TokenTree2"];
15 | assertNoMsg(check, TEST);
16 | }
17 | }
18 |
19 | enum abstract AvoidIdentifierCheckTests(String) to String {
20 | var TEST = "
21 | abstractAndClass Test {
22 | var a:Int;
23 |
24 | function checkIdent(ident:String, token:TokenTree) {
25 | if (isPosSuppressed(token.pos)) return;
26 | if (avoidIdentifiers.indexOf(ident) < 0) return;
27 | error(ident, token.pos);
28 | }
29 |
30 | @SuppressWarnings('checkstyle:AvoidIdentifier')
31 | function checkIdent2(ident:String, token:TokenTree2) {
32 | if (isPosSuppressed(token.pos)) return;
33 | if (avoidIdentifiers.indexOf(ident) < 0) return;
34 | error2(ident, token.pos);
35 | }
36 | }";
37 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/type/TypeCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.type;
2 |
3 | class TypeCheckTest extends CheckTestCase {
4 | @Test
5 | public function testClassVar() {
6 | assertMsg(new TypeCheck(), TEST1, 'Variable "_a" type not specified');
7 | }
8 |
9 | @Test
10 | public function testStaticClassVar() {
11 | assertMsg(new TypeCheck(), TEST2, 'Variable "A" type not specified');
12 | }
13 |
14 | @Test
15 | public function testEnumAbstract() {
16 | assertNoMsg(new TypeCheck(), TEST3);
17 | assertMsg(new TypeCheck(), TEST4, 'Variable "VALUE" type not specified');
18 |
19 | var check = new TypeCheck();
20 | check.ignoreEnumAbstractValues = false;
21 | assertMsg(check, TEST3, 'Variable "VALUE" type not specified');
22 | }
23 | }
24 |
25 | enum abstract TypeCheckTests(String) to String {
26 | var TEST1 = "
27 | class Test {
28 | var _a;
29 |
30 | @SuppressWarnings('checkstyle:Type')
31 | var _b;
32 | }";
33 | var TEST2 = "
34 | class Test {
35 | static inline var A = 1;
36 | }";
37 | var TEST3 = "
38 | enum
39 | abstract Test(Int) {
40 | var VALUE = 0;
41 | }";
42 | var TEST4 = "
43 | enum
44 | abstract Test(Int) {
45 | static inline var VALUE = 0;
46 | }";
47 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/whitespace/ArrayAccessCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.whitespace;
2 |
3 | class ArrayAccessCheckTest extends CheckTestCase {
4 | @Test
5 | public function testSpaceBefore() {
6 | assertMsg(new ArrayAccessCheck(), TEST1, "Space between array and [");
7 | }
8 |
9 | @Test
10 | public function testSpaceInside() {
11 | var check = new ArrayAccessCheck();
12 | assertMsg(check, TEST2, "Space between [ and index");
13 | assertMsg(check, TEST3, "Space between index and ]");
14 | assertMessages(check, TEST4, ["Space between [ and index", "Space between index and ]"]);
15 | }
16 |
17 | @Test
18 | public function testAllowSpaceInside() {
19 | var check = new ArrayAccessCheck();
20 | check.spaceBefore = true;
21 | check.spaceInside = true;
22 | assertNoMsg(check, TEST1);
23 | assertNoMsg(check, TEST2);
24 | assertNoMsg(check, TEST3);
25 | assertNoMsg(check, TEST4);
26 | }
27 |
28 | @Test
29 | public function testCorrectUsage() {
30 | var check = new ArrayAccessCheck();
31 | assertNoMsg(check, TEST5);
32 | }
33 | }
34 |
35 | enum abstract ArrayAccessCheckTests(String) to String {
36 | var TEST1 = "
37 | class Test {
38 |
39 | var a:Array = [];
40 |
41 | function a() {
42 | a [0] = 1;
43 | }
44 | }";
45 | var TEST2 = "
46 | class Test {
47 |
48 | var a:Array = [];
49 |
50 | function a() {
51 | a[ 0] = 1;
52 | }
53 | }";
54 | var TEST3 = "
55 | class Test {
56 |
57 | var a:Array = [];
58 |
59 | function a() {
60 | a[0 ] = 1;
61 | }
62 | }";
63 | var TEST4 = "
64 | class Test {
65 |
66 | var a:Array = [];
67 |
68 | function a() {
69 | a[ 0 ] = 1;
70 | }
71 | }";
72 | var TEST5 = "
73 | class Test {
74 |
75 | var a:Array = [];
76 |
77 | function a() {
78 | a[0] = 1;
79 | }
80 | }";
81 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/whitespace/OperatorWrapCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.whitespace;
2 |
3 | class OperatorWrapCheckTest extends CheckTestCase {
4 | static inline var MSG_PLUS_EOL:String = 'Token "+" must be at the end of the line';
5 | static inline var MSG_PLUS_NL:String = 'Token "+" must be on a new line';
6 | static inline var MSG_LT_NL:String = 'Token "<" must be on a new line';
7 | static inline var MSG_GT_NL:String = 'Token ">" must be on a new line';
8 |
9 | @Test
10 | public function testCorrectWrap() {
11 | var check = new OperatorWrapCheck();
12 | assertNoMsg(check, CORRECT_EOL_WRAP);
13 | assertNoMsg(check, TYPE_PARAM);
14 | assertNoMsg(check, TYPEDEF_EXTENSION);
15 | assertNoMsg(check, NEGATIVE_VARS);
16 | assertNoMsg(check, NEG_OPERATOR);
17 | }
18 |
19 | @Test
20 | public function testIncorrectWrap() {
21 | var check = new OperatorWrapCheck();
22 | assertMsg(check, CORRECT_NL_WRAP_PLUS, MSG_PLUS_EOL);
23 | }
24 |
25 | @Test
26 | public function testOptionNL() {
27 | var check = new OperatorWrapCheck();
28 | check.option = NL;
29 | assertNoMsg(check, CORRECT_NL_WRAP_PLUS);
30 | assertNoMsg(check, CORRECT_NL_WRAP_GT);
31 | assertNoMsg(check, TYPE_PARAM);
32 |
33 | assertMessages(check, CORRECT_EOL_WRAP, [MSG_PLUS_NL, MSG_LT_NL, MSG_GT_NL]);
34 | }
35 | }
36 |
37 | enum abstract OperatorWrapCheckTests(String) to String {
38 | var CORRECT_EOL_WRAP = "
39 | class Test {
40 | function test(param1:String, param2:String) {
41 | var test = test1 +
42 | test2;
43 | test = test1 + test2;
44 | test = a < b;
45 | test = a <
46 | b;
47 | test = a >
48 | b;
49 | test = a > b;
50 | }
51 | function foo():Array {
52 | trace('test');
53 | }
54 | }";
55 | var CORRECT_NL_WRAP_PLUS = "
56 | class Test {
57 | function test() {
58 | var test = test1
59 | + test2;
60 | }
61 | }";
62 | var CORRECT_NL_WRAP_GT = "
63 | class Test {
64 | function test() {
65 | return a
66 | < b;
67 | }
68 | }";
69 | var TYPE_PARAM = "
70 | class Test {
71 | function foo():Array
72 | {
73 | trace('test');
74 | }
75 | }";
76 | var TYPEDEF_EXTENSION = "
77 | typedef Point = {
78 | > Cord,
79 | y:Int
80 | }";
81 | var NEGATIVE_VARS = "
82 | class Test {
83 | function test() {
84 | var rest = if (neg) {
85 | -noFractions;
86 | }
87 | else {
88 | noFractions;
89 | }
90 | do
91 | -a
92 | while(true);
93 | }
94 | }";
95 | var NEG_OPERATOR = "
96 | class Test {
97 | function test() {
98 | var x =
99 | !x;
100 | }
101 | }";
102 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/whitespace/TabForAligningCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.whitespace;
2 |
3 | import checkstyle.SeverityLevel;
4 |
5 | class TabForAligningCheckTest extends CheckTestCase {
6 | @Test
7 | public function testTab() {
8 | var check = new TabForAligningCheck();
9 | check.severity = SeverityLevel.INFO;
10 | assertMsg(check, TEST1, "Tab after non-space character, use space for aligning");
11 | }
12 |
13 | @Test
14 | public function testMultiline() {
15 | var check = new TabForAligningCheck();
16 | check.severity = SeverityLevel.INFO;
17 | assertNoMsg(check, TEST2);
18 | }
19 | }
20 |
21 | enum abstract TabForAligningCheckTests(String) to String {
22 | var TEST1 = "
23 | class Test {
24 | static inline var TAB_FOR_ALIGNING_TEST:Int = 1;
25 |
26 | }";
27 | var TEST2 = "
28 | class Test {
29 | public function test() {
30 | var a:Array = ['one', 'two',
31 | 'three'];
32 | }
33 | }";
34 | }
--------------------------------------------------------------------------------
/test/checkstyle/checks/whitespace/TrailingWhitespaceCheckTest.hx:
--------------------------------------------------------------------------------
1 | package checkstyle.checks.whitespace;
2 |
3 | import checkstyle.SeverityLevel;
4 |
5 | class TrailingWhitespaceCheckTest extends CheckTestCase {
6 | @Test
7 | public function test() {
8 | var check = new TrailingWhitespaceCheck();
9 | check.severity = SeverityLevel.INFO;
10 | assertMsg(check, TEST1, "Trailing whitespace");
11 | }
12 | }
13 |
14 | enum abstract TrailingWhitespaceCheckTests(String) to String {
15 | var TEST1 = "
16 | class Test {
17 | public function test() {} " + "
18 | }";
19 | }
--------------------------------------------------------------------------------
/test/import.hx:
--------------------------------------------------------------------------------
1 | import haxe.PosInfos;
2 | import utest.Assert;
3 | import utest.ITest;
--------------------------------------------------------------------------------
/test/misc/CheckerTest.hx:
--------------------------------------------------------------------------------
1 | package misc;
2 |
3 | import checkstyle.Checker;
4 |
5 | class CheckerTest implements ITest {
6 | public function new() {}
7 |
8 | @Test
9 | public function testEmptyLinesIdx() {
10 | var checker:Checker = new Checker();
11 |
12 | throwsBadOffset(checker, 0);
13 | throwsBadOffset(checker, 100);
14 | throwsBadOffset(checker, -100);
15 | }
16 |
17 | @Test
18 | public function testOneLinesIdx() {
19 | var checker:Checker = new Checker();
20 | checker.linesIdx.push({l: 0, r: 100});
21 |
22 | checkLinePos(checker, 0, 0, 0);
23 | checkLinePos(checker, 50, 0, 50);
24 | checkLinePos(checker, 100, 0, 100);
25 | throwsBadOffset(checker, 101);
26 | throwsBadOffset(checker, -100);
27 | }
28 |
29 | @Test
30 | public function testMultipleLinesIdx() {
31 | var checker:Checker = new Checker();
32 | checker.linesIdx.push({l: 0, r: 100});
33 | checker.linesIdx.push({l: 101, r: 200});
34 | checker.linesIdx.push({l: 201, r: 300});
35 | checker.linesIdx.push({l: 301, r: 400});
36 | checker.linesIdx.push({l: 401, r: 500});
37 | checker.linesIdx.push({l: 501, r: 600});
38 | checker.linesIdx.push({l: 601, r: 700});
39 | checker.linesIdx.push({l: 701, r: 800});
40 |
41 | checkLinePos(checker, 0, 0, 0);
42 | checkLinePos(checker, 50, 0, 50);
43 | checkLinePos(checker, 100, 0, 100);
44 | checkLinePos(checker, 150, 1, 49);
45 | checkLinePos(checker, 250, 2, 49);
46 | checkLinePos(checker, 350, 3, 49);
47 | checkLinePos(checker, 450, 4, 49);
48 | checkLinePos(checker, 550, 5, 49);
49 | checkLinePos(checker, 650, 6, 49);
50 | checkLinePos(checker, 750, 7, 49);
51 | throwsBadOffset(checker, 801);
52 | throwsBadOffset(checker, -100);
53 | }
54 |
55 | function checkLinePos(checker:Checker, ofs:Int, expectedLine:Int, expectedOfs:Int, ?pos:PosInfos) {
56 | var linePos:LinePos = checker.getLinePos(ofs);
57 |
58 | Assert.notNull(linePos, pos);
59 | Assert.equals(expectedLine, linePos.line, pos);
60 | Assert.equals(expectedOfs, linePos.ofs, pos);
61 | }
62 |
63 | function throwsBadOffset(checker:Checker, ofs:Int, ?pos:PosInfos) {
64 | try {
65 | checker.getLinePos(ofs);
66 | Assert.fail("line pos calculation should fail", pos);
67 | }
68 | catch (e:Any) {
69 | Assert.equals("Bad offset", '$e', pos);
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/test/misc/ExtensionsTest.hx:
--------------------------------------------------------------------------------
1 | package misc;
2 |
3 | import checkstyle.checks.CheckTestCase;
4 | import checkstyle.checks.whitespace.IndentationCharacterCheck;
5 |
6 | class ExtensionsTest extends CheckTestCase {
7 | @Test
8 | public function testExtensions() {
9 | assertNoMsg(new IndentationCharacterCheck(), TEST1);
10 | }
11 | }
12 |
13 | enum abstract ExtensionsTests(String) to String {
14 | var TEST1 = "
15 | typedef TypedefName = {
16 | > OneTypedef,
17 | > OtherTypedef,
18 | }";
19 | }
--------------------------------------------------------------------------------
/testAndResources.hxml:
--------------------------------------------------------------------------------
1 | build/commonTest.hxml
2 | build/commonCoverage.hxml
3 | -x TestMain
4 |
5 | -cmd neko run -s src -s test -s schema -s build -p resources/static-analysis.txt
6 | -cmd neko run -s src -s test -s schema -s build -r xml
7 | -cmd neko run --default-config resources/default-config.json
8 | -cmd neko run -c resources/default-config.json
9 |
--------------------------------------------------------------------------------
/testCoverage.hxml:
--------------------------------------------------------------------------------
1 | build/commonTest.hxml
2 | build/commonCoverage.hxml
3 | -x TestMain
4 |
--------------------------------------------------------------------------------
/testJava.hxml:
--------------------------------------------------------------------------------
1 | build/commonTest.hxml
2 | build/commonCoverage.hxml
3 |
4 | --jvm out/TestMain.jar
5 | -main TestMain
6 |
7 | -cmd java -jar out/TestMain.jar
8 |
--------------------------------------------------------------------------------
/uglifyCheckstyle.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | mkdir -p bin
4 |
5 | npx uglify-js-es6 haxecheckstyle.js -o bin/checkstyle.uglify.js
6 |
7 | echo '#!/usr/bin/env node' > bin/checkstyle.js
8 | echo "" >> bin/checkstyle.js
9 | cat bin/checkstyle.uglify.js >> bin/checkstyle.js
10 | chmod 755 bin/checkstyle.js
11 |
12 | rm bin/checkstyle.uglify.js
13 |
--------------------------------------------------------------------------------