diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d384448..6322099f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,12 @@ - New check DocCommentStyle [#440](https://github.com/HaxeCheckstyle/haxe-checkstyle/issues/440) - New check FieldDocComment [#442](https://github.com/HaxeCheckstyle/haxe-checkstyle/issues/442) - New check TypeDocComment [#440](https://github.com/HaxeCheckstyle/haxe-checkstyle/issues/440) +- Added relaxed mode to ConfigParser, fixes [#441](https://github.com/HaxeCheckstyle/haxe-checkstyle/issues/441) ([#443](https://github.com/HaxeCheckstyle/haxe-checkstyle/issues/443)) - Fixed handling of comments between types in ExtendedEmptyLines [#440](https://github.com/HaxeCheckstyle/haxe-checkstyle/issues/440) - Fixed unittest and coverage reporting for Haxe 4 [#442](https://github.com/HaxeCheckstyle/haxe-checkstyle/issues/442) +- Fixed indentation calculation for functions bodys without curly braces [#443](https://github.com/HaxeCheckstyle/haxe-checkstyle/issues/443) +- Fixed segmentaion faults in NeedBraces and CatchParameterName checks [#443](https://github.com/HaxeCheckstyle/haxe-checkstyle/issues/443) +- Changed message of NestedForLoop check [#443](https://github.com/HaxeCheckstyle/haxe-checkstyle/issues/443) - Refactored `Checker.getLinePos` to use binary search, reduces runtime from O(N/2) to O(log N) [#439](https://github.com/HaxeCheckstyle/haxe-checkstyle/issues/439) ## version 2.4.1 (2018-06-14) diff --git a/src/checkstyle/Main.hx b/src/checkstyle/Main.hx index 1e1300ce..b5923a4d 100644 --- a/src/checkstyle/Main.hx +++ b/src/checkstyle/Main.hx @@ -94,6 +94,7 @@ class Main { } } else configParser.paths.push("/code"); + configParser.validateMode = RELAXED; if (defaultConfig.config != null) configPath = defaultConfig.config; if (defaultConfig.exclude != null) excludePath = defaultConfig.exclude; diff --git a/src/checkstyle/checks/block/NeedBracesCheck.hx b/src/checkstyle/checks/block/NeedBracesCheck.hx index f7d5bac6..d6d9a9f0 100644 --- a/src/checkstyle/checks/block/NeedBracesCheck.hx +++ b/src/checkstyle/checks/block/NeedBracesCheck.hx @@ -61,6 +61,7 @@ class NeedBracesCheck extends Check { checkIfChild(tok); case Kwd(KwdElse): var firstChild = tok.getFirstChild(); + if (firstChild == null) continue; if (firstChild.is(Kwd(KwdIf))) checkIfChild(firstChild); else checkLastChild(tok); case Kwd(KwdFunction): @@ -147,6 +148,7 @@ class NeedBracesCheck extends Check { } function checkNoBraces(parent:TokenTree, child:TokenTree) { + if ((parent == null) || (child == null)) return; var minLine:LinePos = checker.getLinePos(parent.pos.min); var maxLine:LinePos = checker.getLinePos(child.getPos().max); var singleLine:Bool = (minLine.line == maxLine.line); @@ -157,11 +159,11 @@ class NeedBracesCheck extends Check { } else { if (singleLine) { - logPos('Body of "$parent" on same line', child.pos); + logPos('Body of "$parent" on same line', child.getPos()); return; } } - logPos('No braces used for body of "$parent"', child.pos); + logPos('No braces used for body of "$parent"', child.getPos()); } function checkIfElseSingleline(parent:TokenTree, child:TokenTree):Bool { diff --git a/src/checkstyle/checks/coding/NestedForDepthCheck.hx b/src/checkstyle/checks/coding/NestedForDepthCheck.hx index c4a1d732..eb691ae0 100644 --- a/src/checkstyle/checks/coding/NestedForDepthCheck.hx +++ b/src/checkstyle/checks/coding/NestedForDepthCheck.hx @@ -56,7 +56,7 @@ class NestedForDepthCheck extends Check { } function warnNestedForDepth(depth:Int, pos:Position) { - logPos('Nested for depth is $depth (max allowed is ${max})', pos); + logPos('Nested loop depth is $depth (max allowed is ${max})', pos); } override public function detectableInstances():DetectableInstances { diff --git a/src/checkstyle/checks/naming/CatchParameterNameCheck.hx b/src/checkstyle/checks/naming/CatchParameterNameCheck.hx index ec8c98bd..e1d407cf 100644 --- a/src/checkstyle/checks/naming/CatchParameterNameCheck.hx +++ b/src/checkstyle/checks/naming/CatchParameterNameCheck.hx @@ -24,7 +24,9 @@ class CatchParameterNameCheck extends Check { for (tkn in catchTokens) { for (item in tkn.children) { - switch (item.getFirstChild().tok) { + var child:TokenTree = item.getFirstChild(); + if (child == null) continue; + switch (child.tok) { case Const(CIdent(name)): if (item.is(POpen)) { if (!formatRE.match(name)) logPos('"$name" must match pattern "~/${format}/"', item.pos); diff --git a/src/checkstyle/checks/whitespace/IndentationCheck.hx b/src/checkstyle/checks/whitespace/IndentationCheck.hx index f2373a78..08dc34f9 100644 --- a/src/checkstyle/checks/whitespace/IndentationCheck.hx +++ b/src/checkstyle/checks/whitespace/IndentationCheck.hx @@ -136,6 +136,7 @@ class IndentationCheck extends Check { Sharp("elseif"), Sharp("end"), Sharp("error"), + Kwd(KwdFunction), Kwd(KwdIf), Kwd(KwdElse), Kwd(KwdFor), @@ -151,6 +152,8 @@ class IndentationCheck extends Check { calcLineIndentationBkOpen(token, lineIndentation); case BrOpen: increaseBlockIndent(token, lineIndentation); + case Kwd(KwdFunction): + calcLineIndentationFunction(token, lineIndentation); case Kwd(KwdIf), Kwd(KwdElse): calcLineIndentationIf(token, lineIndentation); case Kwd(KwdFor), Kwd(KwdDo), Kwd(KwdWhile): @@ -182,6 +185,13 @@ class IndentationCheck extends Check { increaseBlockIndent(token, lineIndentation); } + function calcLineIndentationFunction(token:TokenTree, lineIndentation:Array) { + var body:TokenTree = TokenTreeAccessHelper.access(token).firstChild().lastChild().token; + if (body == null) return; + if (body.is(BrOpen)) return; + increaseIndentIfNextLine(token, body, lineIndentation); + } + function calcLineIndentationIf(token:TokenTree, lineIndentation:Array) { switch (token.tok) { case Kwd(KwdIf): diff --git a/src/checkstyle/config/ConfigParser.hx b/src/checkstyle/config/ConfigParser.hx index 21e0dc9a..16bddcfa 100644 --- a/src/checkstyle/config/ConfigParser.hx +++ b/src/checkstyle/config/ConfigParser.hx @@ -19,14 +19,15 @@ class ConfigParser { public var overrideCheckerThreads:Int; public var info:ChecksInfo; public var checker:Checker; + public var validateMode:ConfigValidateMode; var seenConfigPaths:Array; - var failWith:String -> Void; + var failWithCallback:String -> Void; public function new(failCallback:String -> Void) { info = new ChecksInfo(); checker = new Checker(); - failWith = failCallback; + failWithCallback = failCallback; paths = []; allExcludes = []; @@ -34,6 +35,7 @@ class ConfigParser { excludesMap = new Map(); numberOfCheckerThreads = 5; overrideCheckerThreads = 0; + validateMode = STRICT; } public function loadConfig(path:String) { @@ -151,7 +153,11 @@ class ConfigParser { function createCheck(checkConf:CheckConfig):Check { var check:Check = info.build(checkConf.type); if (check == null) { - Sys.stdout().writeString('Unknown check \'${checkConf.type}\''); + switch (validateMode) { + case STRICT: + failWith('Unknown check "${checkConf.type}"'); + case RELAXED: + } return null; } checker.addCheck(check); @@ -167,6 +173,7 @@ class ConfigParser { var val = Reflect.field(checkConf.props, prop); if (!checkFields.contains(prop)) { failWith('Check ${check.getModuleName()} has no property named \'$prop\''); + continue; } try { check.configureProperty(prop, val); @@ -190,7 +197,7 @@ class ConfigParser { function validateDefines(defines:Array) { for (define in defines) { - if (define.split("=").length > 2) throw "Found a define with more than one = sign: '" + define + "'"; + if (define.split("=").length > 2) failWith("Found a define with more than one = sign: '" + define + "'"); } } @@ -235,4 +242,16 @@ class ConfigParser { } return count; } + + function failWith(msg:String) { + switch (validateMode) { + case STRICT: failWithCallback(msg); + case RELAXED: + } + } +} + +enum ConfigValidateMode { + STRICT; + RELAXED; } \ No newline at end of file diff --git a/test/checks/coding/NestedForDepthCheckTest.hx b/test/checks/coding/NestedForDepthCheckTest.hx index b7958cf6..82b2d682 100644 --- a/test/checks/coding/NestedForDepthCheckTest.hx +++ b/test/checks/coding/NestedForDepthCheckTest.hx @@ -13,7 +13,7 @@ class NestedForDepthCheckTest extends CheckTestCase { @Test public function testDefaultTooMany() { var check = new NestedForDepthCheck(); - assertMsg(check, TEST2, "Nested for depth is 2 (max allowed is 1)"); + assertMsg(check, TEST2, "Nested loop depth is 2 (max allowed is 1)"); } @Test @@ -26,7 +26,7 @@ class NestedForDepthCheckTest extends CheckTestCase { check.max = 0; assertNoMsg(check, TEST1); - assertMsg(check, TEST2, "Nested for depth is 1 (max allowed is 0)"); + assertMsg(check, TEST2, "Nested loop depth is 1 (max allowed is 0)"); } } diff --git a/test/checks/whitespace/IndentationCheckTest.hx b/test/checks/whitespace/IndentationCheckTest.hx index 38c4b669..a7f95a10 100644 --- a/test/checks/whitespace/IndentationCheckTest.hx +++ b/test/checks/whitespace/IndentationCheckTest.hx @@ -10,6 +10,7 @@ class IndentationCheckTest extends CheckTestCase { var check = new IndentationCheck(); check.severity = SeverityLevel.INFO; assertNoMsg(check, CORRECT_TAB_INDENT); + assertNoMsg(check, FUNCTION_BODY_NO_BRACES); assertMsg(check, CORRECT_SPACE_INDENT, 'Indentation mismatch: expected: "\\t"[1], actual: no indentation'); } @@ -301,4 +302,10 @@ class Test { /* * test comment */"; + + var FUNCTION_BODY_NO_BRACES = " +class Test { + public function toString() + return 'Test class'; +}"; } \ No newline at end of file diff --git a/test/config/ConfigParserTest.hx b/test/config/ConfigParserTest.hx index f3be7965..f44d04e5 100644 --- a/test/config/ConfigParserTest.hx +++ b/test/config/ConfigParserTest.hx @@ -173,4 +173,36 @@ class ConfigParserTest { Assert.areEqual("exclude configuration file has unknown version: 0", failMessage); } + + @Test + public function testValidateMode() { + var failMessage:String = ""; + var configParser:ConfigParser = new ConfigParser(function (message:String) { + failMessage = message; + }); + configParser.validateMode = RELAXED; + + Assert.isNotNull(configParser.checker.checks); + Assert.isTrue(configParser.checker.checks.length == 0); + + var config:Config = { + version: 0, + checks: [{ + "type": "non existing check name" + }, + { + "type": "Trace", + "props": { + "non_existing_property": 100 + } + }] + }; + configParser.parseAndValidateConfig(config, LOCAL_PATH); + + Assert.areEqual("", failMessage); + + configParser.validateMode = STRICT; + configParser.parseAndValidateConfig(config, LOCAL_PATH); + Assert.areEqual("Check Trace has no property named 'non_existing_property'", failMessage); + } } \ No newline at end of file