@specs-feup/clava-misra 1.0.3 → 1.0.4

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 (48) hide show
  1. package/dist/MISRATool.d.ts +8 -1
  2. package/dist/MISRATool.d.ts.map +1 -1
  3. package/dist/MISRATool.js +18 -1
  4. package/dist/MISRATool.js.map +1 -1
  5. package/dist/main.js +0 -1
  6. package/dist/main.js.map +1 -1
  7. package/dist/rules/index.d.ts +1 -1
  8. package/dist/rules/index.js +1 -1
  9. package/dist/utils/CallUtils.d.ts.map +1 -1
  10. package/dist/utils/CallUtils.js.map +1 -1
  11. package/dist/utils/FileUtils.d.ts +25 -9
  12. package/dist/utils/FileUtils.d.ts.map +1 -1
  13. package/dist/utils/FileUtils.js +56 -33
  14. package/dist/utils/FileUtils.js.map +1 -1
  15. package/dist/utils/FunctionUtils.d.ts +22 -0
  16. package/dist/utils/FunctionUtils.d.ts.map +1 -1
  17. package/dist/utils/FunctionUtils.js +22 -0
  18. package/dist/utils/FunctionUtils.js.map +1 -1
  19. package/dist/utils/IdentifierUtils.d.ts +49 -0
  20. package/dist/utils/IdentifierUtils.d.ts.map +1 -1
  21. package/dist/utils/IdentifierUtils.js +53 -7
  22. package/dist/utils/IdentifierUtils.js.map +1 -1
  23. package/dist/utils/JoinpointUtils.d.ts +17 -0
  24. package/dist/utils/JoinpointUtils.d.ts.map +1 -1
  25. package/dist/utils/JoinpointUtils.js +17 -0
  26. package/dist/utils/JoinpointUtils.js.map +1 -1
  27. package/dist/utils/ProgramUtils.d.ts +26 -1
  28. package/dist/utils/ProgramUtils.d.ts.map +1 -1
  29. package/dist/utils/ProgramUtils.js +26 -1
  30. package/dist/utils/ProgramUtils.js.map +1 -1
  31. package/dist/utils/TypeDeclUtils.d.ts.map +1 -1
  32. package/dist/utils/TypeDeclUtils.js.map +1 -1
  33. package/dist/utils/VarUtils.d.ts +33 -1
  34. package/dist/utils/VarUtils.d.ts.map +1 -1
  35. package/dist/utils/VarUtils.js +33 -1
  36. package/dist/utils/VarUtils.js.map +1 -1
  37. package/package.json +1 -2
  38. package/src/MISRATool.ts +20 -2
  39. package/src/main.ts +1 -4
  40. package/src/rules/index.ts +1 -1
  41. package/src/utils/CallUtils.ts +0 -3
  42. package/src/utils/FileUtils.ts +66 -38
  43. package/src/utils/FunctionUtils.ts +25 -3
  44. package/src/utils/IdentifierUtils.ts +58 -10
  45. package/src/utils/JoinpointUtils.ts +18 -1
  46. package/src/utils/ProgramUtils.ts +27 -3
  47. package/src/utils/TypeDeclUtils.ts +0 -1
  48. package/src/utils/VarUtils.ts +34 -2
@@ -12,20 +12,62 @@ import path from "path";
12
12
  * @param fileJp - The file to validate.
13
13
  */
14
14
  export function isValidFile(fileJp: FileJp, jpType?: typeof Joinpoint, index?: number) : boolean | Joinpoint | undefined {
15
- const programJp = fileJp.parent as Program;
16
- let copyFile = ClavaJoinPoints.fileWithSource(`temp_misra_${fileJp.name}`, fileJp.code, fileJp.relativeFolderpath);
17
15
  let result: boolean | Joinpoint = true;
18
16
 
17
+ // Create a temporary copy of the file for validation
18
+ const programJp = fileJp.parent as Program;
19
+ let copyFile = ClavaJoinPoints.fileWithSource(`temp_misra_${fileJp.name}`, fileJp.code, fileJp.relativeFolderpath);
19
20
  copyFile = programJp.addFile(copyFile) as FileJp;
21
+
20
22
  try {
21
23
  const rebuiltFile = copyFile.rebuild();
22
- const fileToRemove = Query.searchFrom(programJp, FileJp, {filepath: rebuiltFile.filepath}).first();
23
- if (jpType && index) {
24
+ if (jpType && index) { // If requested, return a specific join point inside the rebuilt file
24
25
  result = Query.searchFrom(rebuiltFile, jpType).get()[index];
25
26
  }
27
+
28
+ // Remove the temporary file
29
+ const fileToRemove = Query.searchFrom(programJp, FileJp, {filepath: rebuiltFile.filepath}).first();
26
30
  fileToRemove?.detach();
27
31
  return result;
28
32
  } catch(error) {
33
+ // On rebuild failure, delete copy file and return false
34
+ copyFile.detach();
35
+ return false;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Checks if the rebuilt version of the file compiles and if the provided call is no longer implicit.
41
+ *
42
+ * @param fileJp The file to analyze
43
+ * @param funcName The function name to search the call
44
+ * @param callIndex The index of the call
45
+ */
46
+ export function isValidFileWithExplicitCall(fileJp: FileJp, funcName: string, callIndex: number, checkNumParams: boolean = false): boolean {
47
+ const programJp = fileJp.parent as Program;
48
+
49
+ // Create a temporary copy of the file for validation
50
+ let copyFile = ClavaJoinPoints.fileWithSource(`temp_misra_${fileJp.name}`, fileJp.code, fileJp.relativeFolderpath);
51
+ copyFile = programJp.addFile(copyFile) as FileJp;
52
+
53
+ try {
54
+ // Rebuild the file to check validity
55
+ const rebuiltFile = copyFile.rebuild();
56
+ const fileToRemove = Query.searchFrom(programJp, FileJp, {filepath: rebuiltFile.filepath}).first() as FileJp;
57
+
58
+ // Locate the function call and check if it is implicit
59
+ const callJp = Query.searchFrom(fileToRemove, Call, {name: funcName}).get().at(callIndex);
60
+ let isExplicitCall = callJp !== undefined && !isCallToImplicitFunction(callJp);
61
+
62
+ if (checkNumParams && isExplicitCall) {
63
+ isExplicitCall = isExplicitCall && callJp!.args.length === callJp!.directCallee.params.length;
64
+ }
65
+
66
+ // Remove the temporary file
67
+ fileToRemove?.detach();
68
+ return isExplicitCall;
69
+
70
+ } catch(error) { // On rebuild failure, delete copy file and return false
29
71
  copyFile.detach();
30
72
  return false;
31
73
  }
@@ -56,7 +98,7 @@ export function removeIncludeFromFile(includeName: string, fileJp: FileJp) {
56
98
  * Returns all files in the program that include a given header file using the `#include` directive
57
99
  *
58
100
  * @param headerName - The name of the header file to search for
59
- * @returns A array of files that include the specified header
101
+ * @returns An array of files that include the specified header
60
102
  */
61
103
  export function findFilesReferencingHeader(headerName: string): FileJp[] {
62
104
  return Query.search(FileJp, (jp) =>{ return getIncludesOfFile(jp).has(headerName)}).get();
@@ -79,37 +121,11 @@ export function getFilesWithCallToImplicitFunction(programJp: Program): FileJp[]
79
121
  }
80
122
 
81
123
  /**
82
- * Checks if the rebuilt version of the file compiles and if the provided call is no longer implicit.
83
- *
84
- * @param fileJp The file to analyze
85
- * @param funcName The function name to search the call
86
- * @param callIndex The index of the call
87
- */
88
- export function isValidFileWithExplicitCall(fileJp: FileJp, funcName: string, callIndex: number, checkNumParams: boolean = false): boolean {
89
- const programJp = fileJp.parent as Program;
90
- let copyFile = ClavaJoinPoints.fileWithSource(`temp_misra_${fileJp.name}`, fileJp.code, fileJp.relativeFolderpath);
91
-
92
- copyFile = programJp.addFile(copyFile) as FileJp;
93
- try {
94
- const rebuiltFile = copyFile.rebuild();
95
- const fileToRemove = Query.searchFrom(programJp, FileJp, {filepath: rebuiltFile.filepath}).first() as FileJp;
96
- const callJp = Query.searchFrom(fileToRemove, Call, {name: funcName}).get().at(callIndex);
97
- let isExplicitCall = callJp !== undefined && !isCallToImplicitFunction(callJp);
98
-
99
- if (checkNumParams && isExplicitCall) {
100
- isExplicitCall = isExplicitCall && callJp!.args.length === callJp!.directCallee.params.length;
101
- }
102
- fileToRemove?.detach();
103
- return isExplicitCall;
104
-
105
- } catch(error) {
106
- copyFile.detach();
107
- return false;
108
- }
109
- }
110
-
111
- /**
124
+ * Inserts an extern declaration of the given function into the file.
112
125
  *
126
+ * @param fileJp The file to modify.
127
+ * @param functionJp The function to declare as extern.
128
+ * @returns The inserted join point, or undefined if the function has no external linkage.
113
129
  */
114
130
  export function addExternFunctionDecl(fileJp: FileJp, functionJp: FunctionJp): Joinpoint | undefined {
115
131
  if (!isExternalLinkageIdentifier(functionJp)) {
@@ -128,14 +144,26 @@ export function addExternFunctionDecl(fileJp: FileJp, functionJp: FunctionJp): J
128
144
  return newExternStmt;
129
145
  }
130
146
 
131
- export function getExternFunctionDecls(fileJp: FileJp) {
147
+ /**
148
+ * Returns all extern function declarations in the given file
149
+ * @param fileJp The file join point
150
+ * @returns An array of functions declared with 'extern'
151
+ */
152
+ export function getExternFunctionDecls(fileJp: FileJp): FunctionJp[] {
132
153
  return Query.searchFrom(fileJp, FunctionJp, {storageClass: StorageClass.EXTERN}).get();
133
154
  }
134
155
 
135
- export function getCallsToLibrary(fileJp: FileJp, libraryFile: string, functionNames: Set<string> = new Set()): Call[] {
156
+ /**
157
+ * Returns function calls from a file that are defined in the provided library header. Optionally filters by function names.
158
+ *
159
+ * @param fileJp The file join point
160
+ * @param libraryName Header filename
161
+ * @param functionNames Optional list of function names to filter
162
+ */
163
+ export function getCallsToLibrary(fileJp: FileJp, libraryName: string, functionNames: Set<string> = new Set()): Call[] {
136
164
  return Query.searchFrom(fileJp, Call, (callJp) =>
137
165
  callJp.function?.isInSystemHeader &&
138
- callJp.function?.filepath.endsWith(libraryFile) &&
166
+ callJp.function?.filepath.endsWith(libraryName) &&
139
167
  (functionNames.size === 0 || functionNames.has(callJp.name))
140
168
  ).get();
141
169
  }
@@ -1,4 +1,4 @@
1
- import { Param, Joinpoint, Varref, FunctionJp, StorageClass, GotoStmt, LabelStmt, FileJp, Call, VariableArrayType } from "@specs-feup/clava/api/Joinpoints.js";
1
+ import { Param, Varref, FunctionJp, StorageClass, GotoStmt, LabelStmt, FileJp, Call, VariableArrayType } from "@specs-feup/clava/api/Joinpoints.js";
2
2
  import Query from "@specs-feup/lara/api/weaver/Query.js";
3
3
  import { findFilesReferencingHeader } from "./FileUtils.js";
4
4
  import { hasDefinedType } from "./JoinpointUtils.js";
@@ -38,12 +38,25 @@ export function getParamReferences($param: Param, functionJp: FunctionJp): Varre
38
38
  return Array.from(new Map([...directRefs, ...refsInVLAFields as Varref[]].map(ref => [ref.ast, ref])).values());
39
39
  }
40
40
 
41
+ /**
42
+ * Gets all label statements in the given function that are never referenced
43
+ * @param func The function to analyze
44
+ * @returns An array of unused labels statements
45
+ */
41
46
  export function getUnusedLabels(func: FunctionJp): LabelStmt[] {
42
47
  return Query.searchFrom(func, LabelStmt).get().filter(label =>
43
48
  Query.searchFrom(func, GotoStmt, { label: jp => jp.astId === label.decl.astId }).get().length === 0
44
49
  );
45
50
  }
46
51
 
52
+ /**
53
+ * Returns the first function definition matching the given name and file path suffix
54
+ *
55
+ * @param functionName Name of the function
56
+ * @param pathSuffix File path suffix
57
+ * @returns The function definition, or undefined if not found
58
+ */
59
+
47
60
  export function findFunctionDef(functionName: string, pathSuffix: string) {
48
61
  const funcDefs = Query.search(FunctionJp, (func) => {
49
62
  try {
@@ -55,11 +68,21 @@ export function findFunctionDef(functionName: string, pathSuffix: string) {
55
68
  return funcDefs.length > 0 ? funcDefs[0] : undefined;
56
69
  }
57
70
 
71
+ /**
72
+ * Finds extern declarations for the given function
73
+ * @param functionJp The function join point
74
+ * @returns List of extern function declarations
75
+ */
58
76
  export function findExternalFunctionDecl(functionJp: FunctionJp): FunctionJp[] {
59
77
  return functionJp.declarationJps
60
78
  .filter((declJp) => declJp.storageClass === StorageClass.EXTERN);
61
79
  }
62
80
 
81
+ /**
82
+ * Checks if the given function is called anywhere in the project
83
+ * @param functionJp The function to evaluate
84
+ * @returns True if the function is used, false otherwise
85
+ */
63
86
  export function isFunctionUsed(functionJp: FunctionJp): boolean {
64
87
  const fileJp = functionJp.getAncestor("file") as FileJp;
65
88
  let referencingFiles: FileJp[];
@@ -71,5 +94,4 @@ export function isFunctionUsed(functionJp: FunctionJp): boolean {
71
94
  referencingFiles = [fileJp];
72
95
  }
73
96
  return referencingFiles.some(fileJp => Query.searchFrom(fileJp, Call, {name: functionJp.name, directCallee: (jp) => jp?.ast === functionJp.ast}).get().length > 0)
74
- }
75
-
97
+ }
@@ -1,7 +1,13 @@
1
1
  import { Joinpoint, Vardecl, StorageClass, FunctionJp, TypedefDecl, LabelStmt, NamedDecl } from "@specs-feup/clava/api/Joinpoints.js";
2
- import { compareLocation, getFileLocation, isTagDecl } from "./JoinpointUtils.js";
2
+ import { compareLocation, isTagDecl } from "./JoinpointUtils.js";
3
3
  import { findDuplicateVarDefinition, findExternalVarRefs, isSameVarDecl } from "./VarUtils.js";
4
4
 
5
+ /**
6
+ * Checks if the given joinpoint is an identifier declaration (variable, function, typedef, label, or tag)
7
+ *
8
+ * @param $jp The joinpoint to evaluate
9
+ * @returns True if the join point is an identifier declaration, false otherwise
10
+ */
5
11
  export function isIdentifierDecl($jp: Joinpoint): boolean {
6
12
  return ($jp instanceof Vardecl && $jp.storageClass !== StorageClass.EXTERN) ||
7
13
  ($jp instanceof FunctionJp && $jp.isImplementation) ||
@@ -10,6 +16,11 @@ export function isIdentifierDecl($jp: Joinpoint): boolean {
10
16
  isTagDecl($jp);
11
17
  }
12
18
 
19
+ /**
20
+ * Retrieves the name of the given joinpoint
21
+ * @param $jp The joinpoint to evaluate
22
+ * @returns The name of the identifier, or undefined if the join point does not represent an identifier
23
+ */
13
24
  export function getIdentifierName($jp: Joinpoint): string | undefined {
14
25
  if ($jp instanceof NamedDecl) {
15
26
  return $jp.name;
@@ -19,6 +30,12 @@ export function getIdentifierName($jp: Joinpoint): string | undefined {
19
30
  return undefined;
20
31
  }
21
32
 
33
+ /**
34
+ * Checks if two joinpoints represent different identifiers with the same name
35
+ * @param identifier1 The first joinpoint to evaluate
36
+ * @param identifier2 The second joinpoint to evaluate
37
+ * @returns True if names match and the nodes differ, otherwise returns false
38
+ */
22
39
  export function areIdentifierNamesEqual(identifier1: Joinpoint, identifier2: Joinpoint) {
23
40
  const name1 = getIdentifierName(identifier1);
24
41
  const name2 = getIdentifierName(identifier2);
@@ -27,21 +44,25 @@ export function areIdentifierNamesEqual(identifier1: Joinpoint, identifier2: Joi
27
44
  return identifier1.ast !== identifier2.ast && name1 === name2;
28
45
  }
29
46
 
47
+ /**
48
+ * Updates the name of an identifier joinpoint
49
+ * @param $jp The joinpoint to rename
50
+ * @param newName the new identifier name
51
+ * @returns True if renaming was successful, false otherwise
52
+ */
30
53
  export function renameIdentifier($jp: Joinpoint, newName: string): boolean {
31
54
  if ($jp instanceof LabelStmt) {
32
55
  $jp.decl.setName(newName);
33
56
  }
34
57
  else if ($jp instanceof Vardecl) {
35
- if (!isExternalLinkageIdentifier($jp)) {
36
- $jp.setName(newName);
37
- } else {
38
- const externalRefs = findExternalVarRefs($jp);
39
- const duplicateDefs = findDuplicateVarDefinition($jp);
40
-
41
- $jp.setName(newName);
58
+ const externalRefs = findExternalVarRefs($jp);
59
+ const duplicateDefs = findDuplicateVarDefinition($jp);
60
+
61
+ $jp.setName(newName);
62
+ if (isExternalLinkageIdentifier($jp)) {
42
63
  externalRefs.forEach((varRef) => varRef.setName(newName));
43
- duplicateDefs.forEach((defJp) => defJp.setName(newName));
44
- }
64
+ duplicateDefs.forEach((defJp) => defJp.setName(newName));
65
+ }
45
66
  }
46
67
  else if ($jp instanceof NamedDecl) {
47
68
  $jp.setName(newName);
@@ -49,6 +70,12 @@ export function renameIdentifier($jp: Joinpoint, newName: string): boolean {
49
70
  return true;
50
71
  }
51
72
 
73
+ /**
74
+ * Checks if a given joinpoint represents an identifier with external linkage
75
+ *
76
+ * @param $jp The joinpoint to evaluate
77
+ * @returns True if the joinpoint has external linkage, false otherwise
78
+ */
52
79
  export function isExternalLinkageIdentifier($jp: Joinpoint): boolean {
53
80
  if (!($jp instanceof FunctionJp || $jp instanceof Vardecl)) {
54
81
  return false;
@@ -60,6 +87,12 @@ export function isExternalLinkageIdentifier($jp: Joinpoint): boolean {
60
87
  return result;
61
88
  }
62
89
 
90
+ /**
91
+ * Checks if a given joinpoint represents an identifier with internal linkage
92
+ *
93
+ * @param $jp The joinpoint to evaluate
94
+ * @returns True if the joinpoint has internal linkage, false otherwise
95
+ */
63
96
  export function isInternalLinkageIdentifier($jp: Joinpoint): boolean {
64
97
  if (!($jp instanceof FunctionJp || $jp instanceof Vardecl)) {
65
98
  return false;
@@ -72,10 +105,25 @@ export function isInternalLinkageIdentifier($jp: Joinpoint): boolean {
72
105
  return result;
73
106
  }
74
107
 
108
+ /**
109
+ * Determines if an identifier is duplicated in a collection of join points
110
+ *
111
+ * @param $jp The identifier to evaluate
112
+ * @param $others Other join points to compare with
113
+ * @returns True if a duplicate exists, false otherwise
114
+ */
75
115
  export function isIdentifierDuplicated($jp: Joinpoint, $others: Joinpoint[]) {
76
116
  return $others.some((identifier) => identifier.astId !== $jp.astId && !isSameVarDecl($jp, identifier) && areIdentifierNamesEqual($jp, identifier));
77
117
  }
78
118
 
119
+ /**
120
+ * Checks if another identifier with the same name is declared before the given joinpoint
121
+ *
122
+ * @param $jp The identifier join point to check
123
+ * @param $others The list of other identifiers to compare with
124
+ * @returns True if a matching identifier is declared earlier, false otherwise.
125
+ */
126
+
79
127
  export function isIdentifierNameDeclaredBefore($jp: Joinpoint, $others: Joinpoint[]) {
80
128
  return $others.some((identifier) => {
81
129
  return identifier.astId !== $jp.astId && !isSameVarDecl($jp, identifier) && compareLocation(identifier, $jp) < 0 && areIdentifierNamesEqual(identifier, $jp)
@@ -30,10 +30,20 @@ export function getBaseType($jp: Joinpoint): Type | undefined {
30
30
  return jpType;
31
31
  }
32
32
 
33
- export function getFilepath($jp: Joinpoint) {
33
+ /**
34
+ * Gets the file path of the given join point.
35
+ * @param $jp The join point
36
+ * @returns The file path string
37
+ */
38
+ export function getFilepath($jp: Joinpoint): string {
34
39
  return $jp instanceof Include ? $jp.parent.filepath : $jp.filepath;
35
40
  }
36
41
 
42
+ /**
43
+ * Returns the exact location of a given join point
44
+ * @param $jp The joinpoint to evaluate
45
+ * @returns A location string containing the filepath, line and column in the format "filepath@line:column"
46
+ */
37
47
  export function getFileLocation($jp: Joinpoint) {
38
48
  if ($jp instanceof Include && $jp.line === undefined) {
39
49
  return `${$jp.parent?.filepath}`;
@@ -41,6 +51,13 @@ export function getFileLocation($jp: Joinpoint) {
41
51
  return `${$jp.filepath}@${$jp.line}:${$jp.column}`
42
52
  }
43
53
 
54
+ /**
55
+ * Orders two join points by their source location: filepath, line, and column
56
+ *
57
+ * @param $jp1 The first join point
58
+ * @param $jp2 The second join point
59
+ * @returns A negative value if $jp1 comes before $jp2, positive if after, or 0 if equal.
60
+ */
44
61
  export function compareLocation($jp1: Joinpoint, $jp2: Joinpoint): number {
45
62
  const filepath1 = getFilepath($jp1), filepath2 = getFilepath($jp2);
46
63
 
@@ -1,14 +1,16 @@
1
- import { Vardecl, FunctionJp, Program, LabelStmt, NamedDecl, StorageClass } from "@specs-feup/clava/api/Joinpoints.js";
1
+ import { Vardecl, FunctionJp, LabelStmt, NamedDecl, StorageClass } from "@specs-feup/clava/api/Joinpoints.js";
2
2
  import Query from "@specs-feup/lara/api/weaver/Query.js";
3
3
  import { isExternalLinkageIdentifier, isIdentifierDecl, isInternalLinkageIdentifier } from "./IdentifierUtils.js";
4
4
 
5
-
6
5
  let cachedInternalLinkageIdentifiers: (FunctionJp | Vardecl)[] | null = null;
7
6
  let cachedExternalLinkageIdentifiers: (FunctionJp | Vardecl)[] | null = null;
8
7
  let cachedExternalLinkageVars: (Vardecl)[] | null = null;
9
8
  let cachedExternalVarRefs: (Vardecl)[] | null = null;
10
9
  let cachedIdentifierDecls: any[] | null = null;
11
10
 
11
+ /**
12
+ * Clears all cached identifiers and variable references
13
+ */
12
14
  export function resetCaches() {
13
15
  cachedInternalLinkageIdentifiers = null;
14
16
  cachedExternalLinkageIdentifiers = null;
@@ -17,6 +19,9 @@ export function resetCaches() {
17
19
  cachedIdentifierDecls = null;
18
20
  }
19
21
 
22
+ /**
23
+ * Clears the cache of external variable references
24
+ */
20
25
  export function resetExternalVarRefs() {
21
26
  cachedExternalVarRefs = null;
22
27
  }
@@ -24,7 +29,8 @@ export function resetExternalVarRefs() {
24
29
  /**
25
30
  * Retrieves all variables and functions that are eligible for `extern` linkage, i.e.,
26
31
  * elements with storage classes that are not `STATIC` or `EXTERN`
27
- * @returns Array of functions and variables that can be declared as external
32
+ *
33
+ * @returns Array of functions and variables that can be declared as external
28
34
  */
29
35
  export function getExternalLinkageIdentifiers(): (FunctionJp | Vardecl)[] {
30
36
  if (cachedExternalLinkageIdentifiers !== null) {
@@ -41,6 +47,11 @@ export function getExternalLinkageIdentifiers(): (FunctionJp | Vardecl)[] {
41
47
  return cachedExternalLinkageIdentifiers;
42
48
  }
43
49
 
50
+ /**
51
+ * Gets identifiers with internal linkage
52
+ *
53
+ * @returns List of functions and variable declarations with internal linkage
54
+ */
44
55
  export function getInternalLinkageIdentifiers(): (FunctionJp | Vardecl)[] {
45
56
  if (cachedInternalLinkageIdentifiers !== null) {
46
57
  return cachedInternalLinkageIdentifiers;
@@ -55,6 +66,11 @@ export function getInternalLinkageIdentifiers(): (FunctionJp | Vardecl)[] {
55
66
  return cachedInternalLinkageIdentifiers;
56
67
  }
57
68
 
69
+ /**
70
+ * Gets identifiers with external linkage
71
+ *
72
+ * @returns List of functions and variable declarations with external linkage
73
+ */
58
74
  export function getExternalLinkageVars(): Vardecl[] {
59
75
  if (cachedExternalLinkageVars != null) {
60
76
  return cachedExternalLinkageVars;
@@ -63,6 +79,11 @@ export function getExternalLinkageVars(): Vardecl[] {
63
79
  return cachedExternalLinkageVars;
64
80
  }
65
81
 
82
+ /**
83
+ * Gets all variable declared with 'extern'
84
+ *
85
+ * @returns List of variable declarations with extern storage class
86
+ */
66
87
  export function getExternalVarRefs(): Vardecl[] {
67
88
  if (cachedExternalVarRefs !== null) {
68
89
  return cachedExternalVarRefs;
@@ -71,6 +92,9 @@ export function getExternalVarRefs(): Vardecl[] {
71
92
  return cachedExternalVarRefs;
72
93
  }
73
94
 
95
+ /**
96
+ * Gets all named declarations and labels
97
+ */
74
98
  export function getIdentifierDecls(): any[] {
75
99
  if (cachedIdentifierDecls !== null) {
76
100
  return cachedIdentifierDecls;
@@ -29,7 +29,6 @@ export function hasTypeDefDecl($jp: Joinpoint): boolean {
29
29
  return getTypeDefDecl($jp) !== undefined;
30
30
  }
31
31
 
32
-
33
32
  /**
34
33
  * Checks if a given joinpoint uses the specified typedef declaration.
35
34
  * @param jp - The joinpoint to check
@@ -20,7 +20,8 @@ export function getVolatileVarRefs($jp: Joinpoint): Varref[] {
20
20
  }
21
21
 
22
22
  /**
23
- * Retrieves all external references of the given variable.
23
+ * Retrieves all external references of the given variable
24
+ *
24
25
  * @param $varDecl variable to match by name.
25
26
  * @returns Array of external references with the same name as the given variable.
26
27
  */
@@ -28,6 +29,12 @@ export function findExternalVarRefs($varDecl: Vardecl): Vardecl[] {
28
29
  return getExternalVarRefs().filter(ref => ref.name === $varDecl.name);
29
30
  }
30
31
 
32
+ /**
33
+ * Identifies functions in the same file that reference the specified variable declaration
34
+ *
35
+ * @param $jp The variable declaration
36
+ * @returns An array of functions that reference the variable
37
+ */
31
38
  export function findReferencingFunctions($jp: Vardecl): FunctionJp[] {
32
39
  const fileJp = $jp.getAncestor("file");
33
40
  const functionsJp = Query.searchFrom(fileJp, FunctionJp).get();
@@ -38,10 +45,23 @@ export function findReferencingFunctions($jp: Vardecl): FunctionJp[] {
38
45
  );
39
46
  }
40
47
 
48
+ /**
49
+ * Finds duplicate definitions of the given variable declaration among external linkage variables
50
+ *
51
+ * @param $jp The variable declaration to evaluate
52
+ * @returns An array of variable declarations representing duplicates
53
+ */
41
54
  export function findDuplicateVarDefinition($jp: Vardecl): Vardecl[] {
42
55
  return getExternalLinkageVars().filter((varDeclJp) => varDeclJp.astId !== $jp.astId && isSameVarDecl(varDeclJp, $jp));
43
56
  }
44
57
 
58
+ /**
59
+ * Checks whether two joinpoints represent the same variable declaration by comparing identifier name, type, and external linkage
60
+ *
61
+ * @param $jp1 The first join point
62
+ * @param $jp2 The second join point
63
+ * @returns True if both are equivalent external variable declarations, false otherwise
64
+ */
45
65
  export function isSameVarDecl($jp1: Joinpoint, $jp2: Joinpoint): boolean {
46
66
  return $jp1 instanceof Vardecl && $jp2 instanceof Vardecl &&
47
67
  isExternalLinkageIdentifier($jp1) && isExternalLinkageIdentifier($jp2) &&
@@ -49,12 +69,25 @@ export function isSameVarDecl($jp1: Joinpoint, $jp2: Joinpoint): boolean {
49
69
  $jp1.type.code === $jp2.type.code
50
70
  }
51
71
 
72
+ /**
73
+ * Checks if the given variable has multiple external linkage declarations across different files
74
+ *
75
+ * @param $jp The variable declaration to evaluate
76
+ * @returns True if multiple external declarations exist, false otherwise
77
+ */
78
+
52
79
  export function hasMultipleExternalLinkDeclarations($jp: Vardecl): boolean {
53
80
  return getExternalLinkageIdentifiers().some(identifier =>
54
81
  isSameVarDecl(identifier, $jp) && identifier.getAncestor("file").ast !== $jp.getAncestor("file").ast
55
82
  );
56
83
  }
57
84
 
85
+ /**
86
+ * Checks whether the given variable declaration is used in its file or in files that include its header.
87
+ *
88
+ * @param varDecl The variable declaration to check
89
+ * @returns True if the variable is referenced, false otherwise
90
+ */
58
91
  export function isVarUsed(varDecl: Vardecl): boolean {
59
92
  const fileJp = varDecl.getAncestor("file") as FileJp;
60
93
  let referencingFiles: FileJp[];
@@ -65,6 +98,5 @@ export function isVarUsed(varDecl: Vardecl): boolean {
65
98
  } else {
66
99
  referencingFiles = [fileJp];
67
100
  }
68
-
69
101
  return referencingFiles.some(fileJp => Query.searchFrom(fileJp, Varref, {name: varDecl.name, decl: (declJp) => declJp?.astId === varDecl.astId}).get().length > 0)
70
102
  }