@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.
- package/CxxSources/lib.cpp +3 -0
- package/CxxSources/lib.h +8 -0
- package/CxxSources/main.cpp +40 -0
- package/README.md +32 -0
- package/TODO.md +1 -0
- package/consumer_order.txt +2 -0
- package/enum_integer_type.txt +0 -0
- package/is_temporary.txt +0 -0
- package/jest.config.js +25 -0
- package/omp.txt +0 -0
- package/package.json +23 -0
- package/src/foo.ts +6 -0
- package/src/main.ts +36 -0
- package/src/misra/MISRAAnalyser.ts +43 -0
- package/src/misra/MISRAPass.ts +85 -0
- package/src/misra/MISRAPassResult.ts +20 -0
- package/src/misra/MISRAReporter.ts +57 -0
- package/src/misra/passes/S10_EssentialTypePass.ts +395 -0
- package/src/misra/passes/S12_ExpressionPass.ts +86 -0
- package/src/misra/passes/S13_SideEffectPass.ts +121 -0
- package/src/misra/passes/S15_ControlFlowPass.ts +108 -0
- package/src/misra/passes/S16_SwitchStatementPass.ts +168 -0
- package/src/misra/passes/S17_FunctionPass.ts +43 -0
- package/src/misra/passes/S18_PointersArraysPass.ts +126 -0
- package/src/misra/passes/S19_OverlappingStoragePass.ts +27 -0
- package/src/misra/passes/S21_StandardLibPass.ts +92 -0
- package/src/misra/passes/S3_CommentPass.ts +40 -0
- package/src/misra/passes/S5_IdentifierPass.ts +66 -0
- package/src/misra/passes/S6_TypePass.ts +32 -0
- package/src/misra/passes/S7_LiteralsConstantsPass.ts +80 -0
- package/src/misra/passes/S8_DeclDefPass.ts +138 -0
- package/src/misra/sections/Section10_EssentialTypeModel.ts +377 -0
- package/src/misra/sections/Section11_PointerTypeConversions.ts +103 -0
- package/src/misra/sections/Section12_Expressions.ts +80 -0
- package/src/misra/sections/Section13_SideEffects.ts +100 -0
- package/src/misra/sections/Section14_ControlStmtExprs.ts +27 -0
- package/src/misra/sections/Section15_ControlFlow.ts +114 -0
- package/src/misra/sections/Section16_SwitchStatements.ts +154 -0
- package/src/misra/sections/Section17_Functions.ts +33 -0
- package/src/misra/sections/Section18_PointersAndArrays.ts +108 -0
- package/src/misra/sections/Section19_OverlappingStorage.ts +18 -0
- package/src/misra/sections/Section20_PreprocessingDirectives.ts +22 -0
- package/src/misra/sections/Section21_StandardLibraries.ts +65 -0
- package/src/misra/sections/Section2_UnusedCode.ts +47 -0
- package/src/misra/sections/Section3_Comments.ts +23 -0
- package/src/misra/sections/Section5_Identifiers.ts +149 -0
- package/src/misra/sections/Section6_Types.ts +26 -0
- package/src/misra/sections/Section7_LiteralsConstants.ts +76 -0
- package/src/misra/sections/Section8_DeclarationsDefinitions.ts +133 -0
- package/src/misra/tests/S10_EssentialTypes.test.ts +253 -0
- package/src/misra/tests/S12_Expressions.test.ts +43 -0
- package/src/misra/tests/S13_SideEffects.test.ts +77 -0
- package/src/misra/tests/S15_ControlFlow.test.ts +144 -0
- package/src/misra/tests/S16_SwitchStatements.test.ts +164 -0
- package/src/misra/tests/S17_Functions.test.ts +46 -0
- package/src/misra/tests/S18_PointersArrays.test.ts +167 -0
- package/src/misra/tests/S19_OverlappingStorage.test.ts +38 -0
- package/src/misra/tests/S3_Comments.test.ts +36 -0
- package/src/misra/tests/S6_Types.test.ts +36 -0
- package/src/misra/tests/S7_LiteralsConstants.test.ts +48 -0
- package/src/misra/tests/utils.ts +47 -0
- package/tsconfig.jest.json +5 -0
- package/tsconfig.json +18 -0
- package/typedoc.config.js +6 -0
- package/types_with_templates.txt +0 -0
package/CxxSources/lib.h
ADDED
@@ -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
|
File without changes
|
package/is_temporary.txt
ADDED
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
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
|
+
}
|