@specs-feup/clava-misra 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CxxSources/lib.cpp +3 -0
  2. package/CxxSources/lib.h +8 -0
  3. package/CxxSources/main.cpp +40 -0
  4. package/README.md +32 -0
  5. package/TODO.md +1 -0
  6. package/consumer_order.txt +2 -0
  7. package/enum_integer_type.txt +0 -0
  8. package/is_temporary.txt +0 -0
  9. package/jest.config.js +25 -0
  10. package/omp.txt +0 -0
  11. package/package.json +23 -0
  12. package/src/foo.ts +6 -0
  13. package/src/main.ts +36 -0
  14. package/src/misra/MISRAAnalyser.ts +43 -0
  15. package/src/misra/MISRAPass.ts +85 -0
  16. package/src/misra/MISRAPassResult.ts +20 -0
  17. package/src/misra/MISRAReporter.ts +57 -0
  18. package/src/misra/passes/S10_EssentialTypePass.ts +395 -0
  19. package/src/misra/passes/S12_ExpressionPass.ts +86 -0
  20. package/src/misra/passes/S13_SideEffectPass.ts +121 -0
  21. package/src/misra/passes/S15_ControlFlowPass.ts +108 -0
  22. package/src/misra/passes/S16_SwitchStatementPass.ts +168 -0
  23. package/src/misra/passes/S17_FunctionPass.ts +43 -0
  24. package/src/misra/passes/S18_PointersArraysPass.ts +126 -0
  25. package/src/misra/passes/S19_OverlappingStoragePass.ts +27 -0
  26. package/src/misra/passes/S21_StandardLibPass.ts +92 -0
  27. package/src/misra/passes/S3_CommentPass.ts +40 -0
  28. package/src/misra/passes/S5_IdentifierPass.ts +66 -0
  29. package/src/misra/passes/S6_TypePass.ts +32 -0
  30. package/src/misra/passes/S7_LiteralsConstantsPass.ts +80 -0
  31. package/src/misra/passes/S8_DeclDefPass.ts +138 -0
  32. package/src/misra/sections/Section10_EssentialTypeModel.ts +377 -0
  33. package/src/misra/sections/Section11_PointerTypeConversions.ts +103 -0
  34. package/src/misra/sections/Section12_Expressions.ts +80 -0
  35. package/src/misra/sections/Section13_SideEffects.ts +100 -0
  36. package/src/misra/sections/Section14_ControlStmtExprs.ts +27 -0
  37. package/src/misra/sections/Section15_ControlFlow.ts +114 -0
  38. package/src/misra/sections/Section16_SwitchStatements.ts +154 -0
  39. package/src/misra/sections/Section17_Functions.ts +33 -0
  40. package/src/misra/sections/Section18_PointersAndArrays.ts +108 -0
  41. package/src/misra/sections/Section19_OverlappingStorage.ts +18 -0
  42. package/src/misra/sections/Section20_PreprocessingDirectives.ts +22 -0
  43. package/src/misra/sections/Section21_StandardLibraries.ts +65 -0
  44. package/src/misra/sections/Section2_UnusedCode.ts +47 -0
  45. package/src/misra/sections/Section3_Comments.ts +23 -0
  46. package/src/misra/sections/Section5_Identifiers.ts +149 -0
  47. package/src/misra/sections/Section6_Types.ts +26 -0
  48. package/src/misra/sections/Section7_LiteralsConstants.ts +76 -0
  49. package/src/misra/sections/Section8_DeclarationsDefinitions.ts +133 -0
  50. package/src/misra/tests/S10_EssentialTypes.test.ts +253 -0
  51. package/src/misra/tests/S12_Expressions.test.ts +43 -0
  52. package/src/misra/tests/S13_SideEffects.test.ts +77 -0
  53. package/src/misra/tests/S15_ControlFlow.test.ts +144 -0
  54. package/src/misra/tests/S16_SwitchStatements.test.ts +164 -0
  55. package/src/misra/tests/S17_Functions.test.ts +46 -0
  56. package/src/misra/tests/S18_PointersArrays.test.ts +167 -0
  57. package/src/misra/tests/S19_OverlappingStorage.test.ts +38 -0
  58. package/src/misra/tests/S3_Comments.test.ts +36 -0
  59. package/src/misra/tests/S6_Types.test.ts +36 -0
  60. package/src/misra/tests/S7_LiteralsConstants.test.ts +48 -0
  61. package/src/misra/tests/utils.ts +47 -0
  62. package/tsconfig.jest.json +5 -0
  63. package/tsconfig.json +18 -0
  64. package/typedoc.config.js +6 -0
  65. package/types_with_templates.txt +0 -0
@@ -0,0 +1,3 @@
1
+ #include <stdio.h>
2
+
3
+ void foo() { printf("Hello, world!"); }
@@ -0,0 +1,8 @@
1
+ #ifndef __LIB_H__
2
+ #define __LIB_H__
3
+
4
+ #include <stdio.h>
5
+
6
+ void foo();
7
+
8
+ #endif // __LIB_H__
@@ -0,0 +1,40 @@
1
+ void f ( void )
2
+ {
3
+ int x, y, z;
4
+ int flag;
5
+ switch (x) {
6
+ case 1:
7
+ z = y+x;
8
+ break;
9
+ case 2:
10
+ z = y-x;
11
+ break;
12
+ default:
13
+ z = 4;
14
+ break;
15
+ }
16
+ switch (flag) {
17
+ case 0:
18
+ x = 2;
19
+ break;
20
+ case 1:
21
+ x = 4;
22
+ break;
23
+ case 2:
24
+ x = 6;
25
+ break;
26
+ }
27
+ switch (z) {
28
+ case 1:
29
+ y = 0;
30
+ break;
31
+ case 6:
32
+ case 42:
33
+ y = 1;
34
+ break;
35
+ case 9139:
36
+ default:
37
+ y = 2;
38
+ break;
39
+ }
40
+ }
package/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # clava-project-template
2
+
3
+ A template for developing projects for Clava in Typescript
4
+
5
+ ## Installing dev environment
6
+
7
+ Execute the following commands to download all the required code:
8
+
9
+ ```bash
10
+ npm install
11
+ ```
12
+
13
+ ## Executing Clava-JS
14
+
15
+ You can execute your project in Clava by running the following on your terminal
16
+
17
+ ```bash
18
+ npm run run
19
+ ```
20
+
21
+ Take a look inside the `scripts` field in the `package.json` file for more information.
22
+
23
+ You can also run tests, get test coverage information and generate documentation for your project.
24
+
25
+ ## Debugging
26
+
27
+ You can get debugging information using a `DEBUG` environment variable.
28
+ This variable is used by the [debug](https://www.npmjs.com/package/debug) module to determine what to expose.
29
+
30
+ ```bash
31
+ DEBUG="*" npm run run
32
+ ```
package/TODO.md ADDED
@@ -0,0 +1 @@
1
+ section 8 has a rule that hasn't been adapted yet
@@ -0,0 +1,2 @@
1
+ ASTConsumer built 1
2
+ ASTConsumer destroyed 1
File without changes
File without changes
package/jest.config.js ADDED
@@ -0,0 +1,25 @@
1
+ import { weaverConfig } from "clava-js/code/WeaverConfiguration.js";
2
+
3
+ const config = {
4
+ preset: "ts-jest/presets/default-esm",
5
+ testEnvironment: "lara-js/jest/jestEnvironment.js",
6
+ testEnvironmentOptions: {
7
+ weaverConfig,
8
+ },
9
+ globalSetup: "lara-js/jest/jestGlobalSetup.js",
10
+ globalTeardown: "lara-js/jest/jestGlobalTeardown.js",
11
+ setupFiles: ["lara-js/jest/setupFiles/sharedJavaModule.js"],
12
+ //notify: true,
13
+ //notifyMode: "always",
14
+ //verbose: true,
15
+ collectCoverage: false,
16
+ coverageDirectory: "coverage",
17
+ coverageReporters: ["text", "lcov"],
18
+ collectCoverageFrom: ["src/**/*[^.d].(t|j)s"],
19
+ coverageProvider: "v8",
20
+ moduleNameMapper: {
21
+ "(.+)\\.js": "$1",
22
+ }
23
+ };
24
+
25
+ export default config;
package/omp.txt ADDED
File without changes
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@specs-feup/clava-misra",
3
+ "version": "1.0.0",
4
+ "author": "L. Sousa",
5
+ "description": "A template for developing projects for Clava in Typescript",
6
+ "type": "module",
7
+ "scripts": {
8
+ "run": "npx clava classic dist/main.js -p CxxSources/",
9
+ "build": "tsc",
10
+ "build:watch": "tsc --watch",
11
+ "lint": "eslint .",
12
+ "docs": "typedoc",
13
+ "test": "cross-env NODE_OPTIONS='$NODE_OPTIONS --experimental-vm-modules' jest --detectOpenHandles --forceExit src",
14
+ "test:cov": "npm run test -- --coverage",
15
+ "test:watch": "npm run test -- --watch"
16
+ },
17
+ "dependencies": {
18
+ "@specs-feup/clava": "^3.0.5",
19
+ "@specs-feup/clava-visualization": "^1.0.4",
20
+ "@specs-feup/lara-visualization": "^1.0.3",
21
+ "@specs-feup/lara": "^3.0.4"
22
+ }
23
+ }
package/src/foo.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { FunctionJp } from "@specs-feup/clava/api/Joinpoints.js";
2
+ import Query from "@specs-feup/lara/api/weaver/Query.js";
3
+
4
+ export function foo() {
5
+ return Query.search(FunctionJp).get().length;
6
+ };
package/src/main.ts ADDED
@@ -0,0 +1,36 @@
1
+ import Query from "@specs-feup/lara/api/weaver/Query.js";
2
+ import { FunctionJp, Joinpoint } from "@specs-feup/clava/api/Joinpoints.js";
3
+ import { foo } from "./foo.js";
4
+ import S16_SwitchStatementPass from "./misra/passes/S16_SwitchStatementPass.js";
5
+ import S15_ControlFlowPass from "./misra/passes/S15_ControlFlowPass.js";
6
+ import MISRAReporter from "./misra/MISRAReporter.js";
7
+ import S10_EssentialTypePass from "./misra/passes/S10_EssentialTypePass.js";
8
+ import AggregatePassResult from "@specs-feup/lara/api/lara/pass/results/AggregatePassResult.js";
9
+ import MISRAPassResult from "./misra/MISRAPassResult.js";
10
+ import S12_ExpressionPass from "./misra/passes/S12_ExpressionPass.js";
11
+ import S17_FunctionPass from "./misra/passes/S17_FunctionPass.js";
12
+ import S13_SideEffectPass from "./misra/passes/S13_SideEffectPass.js";
13
+ import S18_PointersArraysPass from "./misra/passes/S18_PointersArraysPass.js";
14
+
15
+ import VisualizationTool from "@specs-feup/clava-visualization/api/VisualizationTool.js";
16
+
17
+ const pass = new S16_SwitchStatementPass(true, [1, 6, 7]);
18
+ const reporter = new MISRAReporter();
19
+
20
+ console.log(Query.root().dump);
21
+
22
+ const result = reporter.applyPass(
23
+ pass,
24
+ Query.root() as Joinpoint
25
+ ) as AggregatePassResult;
26
+ if (result) {
27
+ result.results.forEach((res) => {
28
+ const reports = (res as MISRAPassResult).reports;
29
+ console.log(reports);
30
+ //reports.forEach(rep => rep.fix?.execute());
31
+ });
32
+ }
33
+
34
+ console.log("GADASDSAD");
35
+
36
+ await VisualizationTool.visualize();
@@ -0,0 +1,43 @@
1
+ import Query from "@specs-feup/lara/api/weaver/Query.js";
2
+ import Analyser from "@specs-feup/clava/api/clava/analysis/Analyser.js";
3
+ import AnalyserResult from "@specs-feup/clava/api/clava/analysis/AnalyserResult.js";
4
+ import { FileJp, Joinpoint, Program } from "@specs-feup/clava/api/Joinpoints.js";
5
+ import ResultFormatManager from "@specs-feup/clava/api/clava/analysis/ResultFormatManager.js"
6
+ import Fix from "@specs-feup/clava/api/clava/analysis/Fix.js";
7
+
8
+ type T = Program | FileJp;
9
+
10
+ export default abstract class MISRAAnalyser extends Analyser {
11
+ #rules: number[];
12
+ #resultFormatManager = new ResultFormatManager();
13
+ protected abstract ruleMapper: Map<number, (jp: T) => void>;
14
+ #results: AnalyserResult[] = [];
15
+
16
+ constructor(rules: number[]) {
17
+ super();
18
+ this.#rules = rules;
19
+ }
20
+
21
+ get rules(): number[] {return this.#rules.map(num => num)};
22
+
23
+ protected logMISRAError(jp: Joinpoint, message: string, fix?: Fix) {
24
+ this.#results.push(new AnalyserResult(`Non-compliant code at ${jp?.filename}@${jp?.line}:${jp?.column}.`, jp, message, fix))
25
+ }
26
+
27
+ analyse($startNode: T = Query.root() as Program) {
28
+ for (const rule of this.rules) {
29
+ const rulePass = this.ruleMapper.get(rule);
30
+ if (rulePass) {
31
+ rulePass($startNode);
32
+ }
33
+ else {
34
+ throw new Error("Analyser doesn't support rule number " + rule)
35
+ }
36
+ }
37
+
38
+ this.#resultFormatManager.setAnalyserResultList(this.#results);
39
+ const fileResult = this.#resultFormatManager.formatResultList($startNode);
40
+
41
+ return fileResult;
42
+ }
43
+ }
@@ -0,0 +1,85 @@
1
+ import { Joinpoint } from "@specs-feup/clava/api/Joinpoints.js";
2
+ import { LaraJoinPoint } from "@specs-feup/lara/api/LaraJoinPoint.js";
3
+ import SimplePass from "@specs-feup/lara/api/lara/pass/SimplePass.js";
4
+ import PassResult from "@specs-feup/lara/api/lara/pass/results/PassResult.js";
5
+ import { Preprocessing, PreprocessingReqs } from "./MISRAReporter.js";
6
+ import MISRAPassResult from "./MISRAPassResult.js";
7
+ import Fix from "@specs-feup/clava/api/clava/analysis/Fix.js";
8
+
9
+ export default abstract class MISRAPass extends SimplePass {
10
+ protected _ruleMapper: Map<number, ($jp: Joinpoint) => void> = new Map();
11
+ private _executedRules: Map<number, boolean> = new Map();
12
+ private _rules: number[];
13
+ private _currentRule: number = -1;
14
+ protected _preprocessing: Preprocessing | undefined;
15
+ private _result: MISRAPassResult | undefined;
16
+ protected abstract _preprocessingReqs: PreprocessingReqs[];
17
+
18
+ get preprocessingReqs() {
19
+ return this._preprocessingReqs;
20
+ }
21
+
22
+ abstract initRuleMapper(): void;
23
+
24
+ setPreprocessing($preprocessing: Preprocessing): void {
25
+ this._preprocessing = $preprocessing;
26
+ }
27
+
28
+ protected logMISRAError(message: string, fix?: Fix) {
29
+ this._result?.addReport({rule: this._currentRule, message, fix});
30
+ }
31
+
32
+ private resetRules(): void {
33
+ this._executedRules.forEach(($value: boolean, $key: number) => {
34
+ this._executedRules.set($key, false);
35
+ }, this);
36
+ }
37
+
38
+ constructor(includeDescendants: boolean = true, rules: number[]) {
39
+ super(includeDescendants);
40
+ this._rules = rules;
41
+ this.initRuleMapper();
42
+
43
+ this._ruleMapper.forEach(($value: ($jp: Joinpoint) => void, $key: number) => {
44
+ this._executedRules.set($key, false);
45
+ }, this);
46
+ }
47
+
48
+ private executeRule($id: number, $jp: Joinpoint) {
49
+ if (!this._ruleMapper.has($id)) {
50
+ throw new Error(`Pass does not support rule ${$id}`);
51
+ }
52
+
53
+ (this._ruleMapper.get($id) as ($jp: Joinpoint) => void)($jp);
54
+ this._executedRules.set($id, true);
55
+ }
56
+
57
+ protected dependsOn($id: number, $jp: Joinpoint) {
58
+ const tempId = this._currentRule;
59
+ if (this._executedRules.get($id) === false) {
60
+ this._currentRule = $id;
61
+ this.executeRule($id, $jp);
62
+ }
63
+ this._currentRule = tempId;
64
+ }
65
+
66
+ abstract matchJoinpoint($jp: LaraJoinPoint): boolean;
67
+
68
+ transformJoinpoint($jp: LaraJoinPoint): MISRAPassResult {
69
+ if (!this._preprocessing) {
70
+ throw new Error("Preprocessing object has not been set.");
71
+ }
72
+
73
+ this._result = new MISRAPassResult(this, $jp);
74
+ this.resetRules();
75
+ this._rules.forEach($id => {
76
+ this._currentRule = $id;
77
+ this.executeRule($id, $jp as Joinpoint);
78
+ }, this);
79
+
80
+ return this._result;
81
+ }
82
+
83
+ protected abstract _name: string;
84
+
85
+ }
@@ -0,0 +1,20 @@
1
+ import Fix from "@specs-feup/clava/api/clava/analysis/Fix.js";
2
+ import PassResult from "@specs-feup/lara/api/lara/pass/results/PassResult.js";
3
+
4
+ export interface MISRAReport {
5
+ rule: number,
6
+ message: string,
7
+ fix?: Fix
8
+ }
9
+
10
+ export default class MISRAPassResult extends PassResult {
11
+ protected _reports: MISRAReport[] = [];
12
+
13
+ get reports(): MISRAReport[] {
14
+ return this._reports;
15
+ }
16
+
17
+ addReport($report: MISRAReport) {
18
+ this._reports.push($report);
19
+ }
20
+ }
@@ -0,0 +1,57 @@
1
+ import { FileJp, FunctionJp, Joinpoint, StorageClass, TypedefNameDecl, Vardecl } from "@specs-feup/clava/api/Joinpoints.js";
2
+ import MISRAPass from "./MISRAPass.js";
3
+ import Query from "@specs-feup/lara/api/weaver/Query.js";
4
+ import PassResult from "@specs-feup/lara/api/lara/pass/results/PassResult.js";
5
+ import AggregatePassResult from "@specs-feup/lara/api/lara/pass/results/AggregatePassResult.js";
6
+ import MISRAPassResult from "./MISRAPassResult.js";
7
+
8
+ export enum PreprocessingReqs {
9
+ TYPEDEF_DECLS = "typedefDecls",
10
+ EXTERNAL_LINKAGE_DECLS = "externalLinkageDecls"
11
+ }
12
+
13
+ export interface Preprocessing {
14
+ typedefDecls?: TypedefNameDecl[],
15
+ externalLinkageDecls?: (FunctionJp | Vardecl)[]
16
+ }
17
+
18
+ export default class MISRAReporter {
19
+ private _preprocessing: Preprocessing = {};
20
+ private _preprocessingMapper: Map<PreprocessingReqs, () => void> = new Map([
21
+ [PreprocessingReqs.TYPEDEF_DECLS, this.initTypedefs.bind(this)],
22
+ [PreprocessingReqs.EXTERNAL_LINKAGE_DECLS, this.initExternals.bind(this)]
23
+ ]);
24
+
25
+ private initTypedefs(): void {
26
+ this._preprocessing.typedefDecls = Query.search(TypedefNameDecl).get();
27
+ }
28
+
29
+ private static hasExternalLinkage($class: StorageClass) {
30
+ return $class !== StorageClass.STATIC && $class !== StorageClass.EXTERN;
31
+ }
32
+
33
+ private initExternals(): void {
34
+ this._preprocessing.externalLinkageDecls = [];
35
+ Query.search(FileJp).get().forEach(file => {
36
+ file.children.forEach(child => {
37
+ if ((child instanceof Vardecl || child instanceof FunctionJp) && MISRAReporter.hasExternalLinkage(child.storageClass)) {
38
+ this._preprocessing.externalLinkageDecls?.push(child);
39
+ }
40
+ }, this);
41
+ }, this);
42
+ }
43
+
44
+ applyPass($pass: MISRAPass, $jp: Joinpoint): AggregatePassResult | undefined {
45
+ $pass.preprocessingReqs.forEach($req => {
46
+ if (!this._preprocessing[$req]) {
47
+ (this._preprocessingMapper.get($req) as () => void)();
48
+ }
49
+ });
50
+
51
+ $pass.setPreprocessing(this._preprocessing);
52
+ const result = $pass.apply($jp) as AggregatePassResult;
53
+ if ((result.results as MISRAPassResult[]).some(res => res.reports.length > 0)) {
54
+ return result;
55
+ }
56
+ }
57
+ }