From 285e14fb4a0de66359bafcd1b435ba54cf16e124 Mon Sep 17 00:00:00 2001 From: Tetsuro Yoshikawa Date: Sun, 24 Jul 2022 18:56:04 +0900 Subject: [PATCH] feat: support php8 for CognitiveComplexityCountableNode. --- src/Language/PHP/ASTKind.ts | 2 ++ ...ts => CognitiveComplexityCountableNode.ts} | 11 +++---- src/Language/PHP/Converter/Complexity.ts | 4 +-- src/Language/PHP/HalsteadCountableNode.ts | 2 ++ .../__tests__/ComplexityCountableNode.test.ts | 30 ++++++++++++------- .../PHP/__tests__/fixtures/example.php | 17 +++++++++++ src/Sabik/DIContainer.ts | 2 +- 7 files changed, 49 insertions(+), 19 deletions(-) rename src/Language/PHP/{ComplexityCountableNode.ts => CognitiveComplexityCountableNode.ts} (75%) diff --git a/src/Language/PHP/ASTKind.ts b/src/Language/PHP/ASTKind.ts index 2042c13..b7670b0 100644 --- a/src/Language/PHP/ASTKind.ts +++ b/src/Language/PHP/ASTKind.ts @@ -56,4 +56,6 @@ export enum ASTKind { USE = 'usegroup', YIELD = 'yield', YIELD_FROM = 'yieldfrom', + MATCH_ARM = 'matcharm', + NULL_SAFE_PROPERTY_LOOKUP = 'nullsafepropertylookup', } diff --git a/src/Language/PHP/ComplexityCountableNode.ts b/src/Language/PHP/CognitiveComplexityCountableNode.ts similarity index 75% rename from src/Language/PHP/ComplexityCountableNode.ts rename to src/Language/PHP/CognitiveComplexityCountableNode.ts index 8c4343b..ae7df01 100644 --- a/src/Language/PHP/ComplexityCountableNode.ts +++ b/src/Language/PHP/CognitiveComplexityCountableNode.ts @@ -8,7 +8,7 @@ type BinNode = PHPParser.Node & { type: string }; type IfNode = PHPParser.Node & { alternate: PHPParser.Node }; @injectable() -export class ComplexityCountableNode implements ComplexityCountableNodeInterface { +export class CognitiveComplexityCountableNode implements ComplexityCountableNodeInterface { private static readonly nestLevelUpKinds = [ ASTKind.IF, ASTKind.CATCH, @@ -29,6 +29,7 @@ export class ComplexityCountableNode implements ComplexityCountableNodeInterface ASTKind.FOR, ASTKind.WHILE, ASTKind.RETURN_IF, + ASTKind.MATCH_ARM, ]; private readonly node: ASTNode; @@ -38,13 +39,13 @@ export class ComplexityCountableNode implements ComplexityCountableNodeInterface } isNestLevelUp() { - return !this.isElse() && ComplexityCountableNode.nestLevelUpKinds.includes(this.node.kind); + return !this.isElse() && CognitiveComplexityCountableNode.nestLevelUpKinds.includes(this.node.kind); } isIncrement() { if (this.isElse()) { return true; - } else if (ComplexityCountableNode.nestingIncrementSyntaxKinds.includes(this.node.kind)) { + } else if (CognitiveComplexityCountableNode.nestingIncrementSyntaxKinds.includes(this.node.kind)) { return true; } else if (this.node.kind === ASTKind.LABEL) { return true; @@ -63,7 +64,7 @@ export class ComplexityCountableNode implements ComplexityCountableNodeInterface return false; } - return ComplexityCountableNode.nestingIncrementSyntaxKinds.includes(this.node.kind); + return CognitiveComplexityCountableNode.nestingIncrementSyntaxKinds.includes(this.node.kind); } private isElse() { @@ -73,6 +74,6 @@ export class ComplexityCountableNode implements ComplexityCountableNodeInterface } getChildren() { - return this.node.getChildren().map((node) => new ComplexityCountableNode(node)); + return this.node.getChildren().map((node) => new CognitiveComplexityCountableNode(node)); } } diff --git a/src/Language/PHP/Converter/Complexity.ts b/src/Language/PHP/Converter/Complexity.ts index 664ba75..dd26dd0 100644 --- a/src/Language/PHP/Converter/Complexity.ts +++ b/src/Language/PHP/Converter/Complexity.ts @@ -1,10 +1,10 @@ import { injectable } from 'inversify'; import { ASTNode } from '../ASTNode'; -import { ComplexityCountableNode } from '../ComplexityCountableNode'; +import { CognitiveComplexityCountableNode } from '../CognitiveComplexityCountableNode'; @injectable() export class Complexity { convert(astNode: ASTNode) { - return new ComplexityCountableNode(astNode); + return new CognitiveComplexityCountableNode(astNode); } } diff --git a/src/Language/PHP/HalsteadCountableNode.ts b/src/Language/PHP/HalsteadCountableNode.ts index e9fadd6..efab59a 100644 --- a/src/Language/PHP/HalsteadCountableNode.ts +++ b/src/Language/PHP/HalsteadCountableNode.ts @@ -65,6 +65,7 @@ export class HalsteadCountableNode implements HalsteadCountableNodeInterface { 'T_DEFAULT', 'T_DO', 'T_IF', + 'T_MATCH', 'T_ELSE', 'T_ELSEIF', 'T_FOR', @@ -115,6 +116,7 @@ export class HalsteadCountableNode implements HalsteadCountableNodeInterface { 'T_DECLARE', 'T_DEC', 'X_OPERATOR_STRING', + 'T_COALESCE', ]; private static readonly operatorStrings = ['+', '/', '*', '-', '%', '&', '|', '^', '~', '@', '`', '!', '.', ',']; diff --git a/src/Language/PHP/__tests__/ComplexityCountableNode.test.ts b/src/Language/PHP/__tests__/ComplexityCountableNode.test.ts index 26444a7..78469fa 100644 --- a/src/Language/PHP/__tests__/ComplexityCountableNode.test.ts +++ b/src/Language/PHP/__tests__/ComplexityCountableNode.test.ts @@ -1,9 +1,9 @@ import { Engine } from 'php-parser'; import { readFileSync } from 'fs'; import { ASTNode } from '../ASTNode'; -import { ComplexityCountableNode } from '../ComplexityCountableNode'; +import { CognitiveComplexityCountableNode } from '../CognitiveComplexityCountableNode'; -describe('ComplexityCountableNode', () => { +describe('CognitiveComplexityCountableNode', () => { const engine = new Engine({ parser: { extractDoc: true, @@ -35,14 +35,16 @@ describe('ComplexityCountableNode', () => { ['function', map.get('function')!.getChildren()[0].getChildren()[0]], ['arrowFunction', map.get('arrowFunction')!.getChildren()[0].getChildren()[0]], ])('should %s is nest level up.', (_, astNode) => { - const actual = new ComplexityCountableNode(astNode); + const actual = new CognitiveComplexityCountableNode(astNode); expect(actual.isNestLevelUp()).toBe(true); }); it('should returns false when elseif or else statement.', () => { - const elseIfActual = new ComplexityCountableNode(map.get('if')!.getChildren()[0].getChildren()[2]); - const elseActual = new ComplexityCountableNode(map.get('if')!.getChildren()[0].getChildren()[2].getChildren()[2]); + const elseIfActual = new CognitiveComplexityCountableNode(map.get('if')!.getChildren()[0].getChildren()[2]); + const elseActual = new CognitiveComplexityCountableNode( + map.get('if')!.getChildren()[0].getChildren()[2].getChildren()[2] + ); expect(elseIfActual.isNestLevelUp()).toBe(false); expect(elseActual.isNestLevelUp()).toBe(false); @@ -57,15 +59,18 @@ describe('ComplexityCountableNode', () => { ['while', map.get('while')!.getChildren()[0]], ['catch', map.get('try')!.getChildren()[0].getChildren().pop()], ['conditional', map.get('conditional')!.getChildren()[0].getChildren()[0]], + ['match', map.get('match')!.getChildren()[0].getChildren()[0].getChildren()[1]], ])('should %s is nesting increment.', (_, astNode) => { - const actual = new ComplexityCountableNode(astNode); + const actual = new CognitiveComplexityCountableNode(astNode); expect(actual.isNestingIncrement()).toBe(true); }); it('should returns false when elseif or else statement.', () => { - const elseIfActual = new ComplexityCountableNode(map.get('if')!.getChildren()[0].getChildren()[2]); - const elseActual = new ComplexityCountableNode(map.get('if')!.getChildren()[0].getChildren()[2].getChildren()[2]); + const elseIfActual = new CognitiveComplexityCountableNode(map.get('if')!.getChildren()[0].getChildren()[2]); + const elseActual = new CognitiveComplexityCountableNode( + map.get('if')!.getChildren()[0].getChildren()[2].getChildren()[2] + ); expect(elseIfActual.isNestingIncrement()).toBe(false); expect(elseActual.isNestingIncrement()).toBe(false); @@ -83,15 +88,18 @@ describe('ComplexityCountableNode', () => { ['ampersand', map.get('ampersand')!.getChildren()[0].getChildren()[0]], ['barbar', map.get('barbar')!.getChildren()[0].getChildren()[0]], ['label', map.get('label')!.getChildren()[1]], + ['match', map.get('match')!.getChildren()[0].getChildren()[0].getChildren()[1]], ])('should %s is increment.', (_, astNode) => { - const actual = new ComplexityCountableNode(astNode); + const actual = new CognitiveComplexityCountableNode(astNode); expect(actual.isIncrement()).toBe(true); }); it('should returns true when elseif or else statement.', () => { - const elseIfActual = new ComplexityCountableNode(map.get('if')!.getChildren()[0].getChildren()[2]); - const elseActual = new ComplexityCountableNode(map.get('if')!.getChildren()[0].getChildren()[2].getChildren()[2]); + const elseIfActual = new CognitiveComplexityCountableNode(map.get('if')!.getChildren()[0].getChildren()[2]); + const elseActual = new CognitiveComplexityCountableNode( + map.get('if')!.getChildren()[0].getChildren()[2].getChildren()[2] + ); expect(elseIfActual.isIncrement()).toBe(true); expect(elseActual.isIncrement()).toBe(true); diff --git a/src/Language/PHP/__tests__/fixtures/example.php b/src/Language/PHP/__tests__/fixtures/example.php index f3bc017..694d468 100644 --- a/src/Language/PHP/__tests__/fixtures/example.php +++ b/src/Language/PHP/__tests__/fixtures/example.php @@ -73,6 +73,23 @@ function function() { function arrowFunction() { return fn() => 1; } + + function nullishCoalescingOperator() { + return null ?? 0; + } + + function optionalChaining() { + $obj = new stdClass(); + return $obj?->b; + } + + function match() { + return match('a') { + 'apple' => 'This food is an apple', + 'bar' => 'This food is a bar', + 'cake' => 'This food is a cake', + }; + } } trait MyTrait { diff --git a/src/Sabik/DIContainer.ts b/src/Sabik/DIContainer.ts index d57bf4b..4e002f0 100644 --- a/src/Sabik/DIContainer.ts +++ b/src/Sabik/DIContainer.ts @@ -36,7 +36,7 @@ import { ComplexityCountableNode } from '../Analyzer/CodeMetricsCalculator/Cogni import { HalsteadCountableNode } from '../Analyzer/CodeMetricsCalculator/Halstead/Adapter/HalsteadCountableNode'; import { LineOfCode as LineOfCodeConverterForTypeScript } from '../Language/TypeScript/Converter/LineOfCode'; import { Halstead as HalsteadConverterForTypeScript } from '../Language/TypeScript/Converter/Halstead'; -import { Complexity as ComplexityConverterForTypeScript } from '../Language/TypeScript/Converter/Complexity'; +import { Complexity as ComplexityConverterForTypeScript } from '../Language/TypeScript/Converter/CognitiveComplexity'; import { ASTGenerator as ASTGeneratorForTypeScript } from '../Language/TypeScript/ASTGenerator'; import { CalculatorForAST } from '../Analyzer/FromASTNode/CalculatorForAST'; import { CalculatorForMetrics } from '../Analyzer/FromOtherMetrics/CalculatorForMetrics';