Skip to content

Commit

Permalink
feat: support php8 for CognitiveComplexityCountableNode.
Browse files Browse the repository at this point in the history
  • Loading branch information
ytetsuro committed Aug 14, 2022
1 parent 5677e0e commit 285e14f
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 19 deletions.
2 changes: 2 additions & 0 deletions src/Language/PHP/ASTKind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,6 @@ export enum ASTKind {
USE = 'usegroup',
YIELD = 'yield',
YIELD_FROM = 'yieldfrom',
MATCH_ARM = 'matcharm',
NULL_SAFE_PROPERTY_LOOKUP = 'nullsafepropertylookup',
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -29,6 +29,7 @@ export class ComplexityCountableNode implements ComplexityCountableNodeInterface
ASTKind.FOR,
ASTKind.WHILE,
ASTKind.RETURN_IF,
ASTKind.MATCH_ARM,
];

private readonly node: ASTNode;
Expand All @@ -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;
Expand All @@ -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() {
Expand All @@ -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));
}
}
4 changes: 2 additions & 2 deletions src/Language/PHP/Converter/Complexity.ts
Original file line number Diff line number Diff line change
@@ -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);
}
}
2 changes: 2 additions & 0 deletions src/Language/PHP/HalsteadCountableNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export class HalsteadCountableNode implements HalsteadCountableNodeInterface {
'T_DEFAULT',
'T_DO',
'T_IF',
'T_MATCH',
'T_ELSE',
'T_ELSEIF',
'T_FOR',
Expand Down Expand Up @@ -115,6 +116,7 @@ export class HalsteadCountableNode implements HalsteadCountableNodeInterface {
'T_DECLARE',
'T_DEC',
'X_OPERATOR_STRING',
'T_COALESCE',
];

private static readonly operatorStrings = ['+', '/', '*', '-', '%', '&', '|', '^', '~', '@', '`', '!', '.', ','];
Expand Down
30 changes: 19 additions & 11 deletions src/Language/PHP/__tests__/ComplexityCountableNode.test.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down
17 changes: 17 additions & 0 deletions src/Language/PHP/__tests__/fixtures/example.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/Sabik/DIContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down

0 comments on commit 285e14f

Please sign in to comment.