CodeNavi Static Analysis Rule Language: Nodes and Node Properties for Code Statements
Source code is parsed into discrete tokens during static analysis, the smallest grammatical units that form programming language syntax. Common token types include keywords (e.g. if, while), identifiers (variable/function names), literals (numeric values, strings), operators (e.g. +, /), and separators (commas, semicolons). CodeNavi maps parsed code elements to standardized nodes, with explicitly defined properties for each node type. Users write inspection rules by combining logical conditions for these nodes and their attributes to match target defect patterns, without requiring knowledge of underlying static analysis implementation details.
Node and Attribute Definition Conventions
All nodes are referenced by their English identifier in CodeNavi DSL for simplified rule writing. A node set represents a collection of logically related nodes, while node attributes also use standardized English names for consistent reference.
Statement Nodes
Programming languages include multiple statement types for different runtime operations. Common statements are shown in the sample below:
// Expression statements: execute assignments, method calls
int userCount = 24;
System.out.println("Static analysis routine running");
// Conditional statements: execute branch logic based on boolean checks
int customerScore = 82;
if (customerScore > 75) {
System.out.println("Premium user tier");
} else {
System.out.println("Standard user tier");
}
// Switch statements: multi-branch selection
int orderStatus = 2;
switch(orderStatus) {
case 1: System.out.println("Pending payment"); break;
case 2: System.out.println("Processing shipment"); break;
default: System.out.println("Unrecognized order state");
}
// Loop statements: repeat code execution
// For loop
for (int idx = 0; idx < 12; idx++) {
System.out.println(idx);
}
// While loop
int counter = 0;
while (counter < 12) {
System.out.println(counter++);
}
// Do-while loop
int retry = 0;
do {
System.out.println(retry++);
} while (retry < 12);
// Jump statements: alter execution flow
// Break
for (int idx = 0; idx < 12; idx++) {
if (idx == 7) break;
System.out.println(idx);
}
// Continue
for (int idx = 0; idx < 12; idx++) {
if (idx %3 ==0) continue;
System.out.println(idx);
}
// Exception handling
try {
int result = 200 / eligibleUserCount;
} catch (ArithmeticException e) {
System.out.println("Cannot calculate discount for zero users");
}
// Return statement
public int getMin(int x, int y) {
return x < y ? x : y;
}
Assign Statement (assignStatement)
Assign statements store the output of an expression or literal value to a target variable, used for variable initialization, state updates, and complex result caching to simplify code readability. Sample code:
int orderAmount = 199;
String userGroup = "premium_" + userId;
Node attributes:
| Name | Description | Value Type | Sample | DSL Rule |
|---|---|---|---|---|
| lhs | Left-hand assignment target | valueAccess node | orderAmount = 199; | assignStatement assign where assign.lhs.name == "orderAmount"; |
| rhs | Right-hand value source | literal, valueAccess, functionCall node | orderAmount = 199; | assignStatement assign where assign.rhs.value == 199; |
Control Flow Statement Nodes
Control flow statements define the execution order of code blocks, supporting conditional branching, repeated execution, exception handlign, and execution flow redirection.
Jump Statements
Jump statements alter normal sequential execution to skip code blocks or redirect execution to other parts of the program.
Continue Statement (continueStatement)
The continue statement skips remaining logic in the current loop iteration and starts the next iteration, typically used to skip processing for elements that do not match filter conditions, reduce nested logic depth, and avoid duplicate processing of already handled records.
Sample code:
for (int idx = 0; idx < 15; idx++) {
// Skip multiples of 3
if (idx %3 == 0) {
continue;
}
System.out.println(idx);
}
Break Statement (breakStatement)
The break statement immediately terminates execution of the innermost enclosing loop or switch block, used to exit loops early when a target condition is met, avoid infinite loops, stop processing once a search target is found, and exit execution when an error state is detected.
Sample code:
for (int idx = 0; idx < 15; idx++) {
if (idx == 7) {
break;
}
System.out.println(idx);
}
Return Statement (returnStatement)
The return statement exits the current function and optionally passes a result value back to the caller, used to return computation outputs, exit functions early when preconditions are not met, simplify conditional logic, and return error states during exception handling.
Sample code:
public int getMin(int x, int y) {
return x < y ? x : y;
}
Node attributes:
| Name | Description | Value Type | Sample | DSL Rule |
|---|---|---|---|---|
| returnValue | Returned value | Any node type | return userId; | returnStatement ret where ret.returnValue.name == "userId"; |
Throw Statement (throwStatement)
The throw statement manually triggers an exception to interrupt normal execution when an invalid state is detected, supporting explicit error propagation, custom error type definition, and enforcement of interface implementation constraints.
Sample code:
throw new IllegalArgumentException("Invalid input parameter value");
Node attributes:
| Name | Description | Value Type | Sample | DSL Rule |
|---|---|---|---|---|
| operand | Thrown exception instance | Node | throw new RuntimeException(); | throwStatement thr where thr.operand is objectCreationExpression; |
Conditional Control (ifBlock)
Conditional control blocks select execution paths based on boolean condition results, supporting dynamic logic branching, feature toggling, state validation, error prevention, and resource management. Sample code:
if (orderAmount > 200) {
System.out.println("Eligible for free shipping");
} else {
System.out.println("Add $15 for standard shipping");
}
Node attributes:
| Name | Description | Value Type | Sample | DSL Rule |
|---|---|---|---|---|
| condition | If conditional expression | binaryOperation node | if (orderAmount > 200) {} | ifBlock ib where ib.condition contain binaryOperation bo where bo.operator == ">"; |
| thenBlock | Code executed when condition evaluates to true | block node | if (orderAmount > 200) { print("Free shipping"); } | ifBlock ib where ib.thenBlock contain stringLiteral sl where sl.value == "Eligible for free shipping"; |
| elseBlock | Code executed when condition evaluates to false | block node | else { print("Shipping fee applied"); } | ifBlock ib where ib.elseBlock contain stringLiteral sl where sl.value == "Add $15 for standard shipping"; |
Switch Control
Switch blocks provide a cleaner alternative to nested if-else chains for multi-branch selection based on discrete value matches, reducing code nesting, improving readability, and simplifying maintenance of multi-condition logic.
Sample code:
switch (orderStatus) {
case 1:
System.out.println("Pending payment confirmation");
break;
case 2:
case 3:
System.out.println("Order processing in progress");
break;
default:
System.out.println("Unknown order state");
}
Switch Block (switchBlock)
Node attributes:
| Name | Description | Value Type | Sample | DSL Rule |
|---|---|---|---|---|
| selector | Value evaluated for case matching | Any node type | switch (orderStatus) {} | switchBlock sw where sw.selector.name == "orderStatus"; |
Case Statement (caseStatement)
DSL rule sample:
caseStatement cs where cs contain numericLiteral;
Default Statement (defaultStatement)
DSL rule sample:
switchBlock sw where sw contain defaultStatement;
Loop Control
Loop control blocks enable repeated execution of code segments for iterative data processing, algorithm implementation, and batch operation handling. Supported loop types include forBlock, forEachBlock, whileBlock, and doWhileBlock.
Loop Block Base Attributes
All loop types share the following common attributes:
| Name | Description | Value Type | Sample | DSL Rule |
|---|---|---|---|---|
| condition | Loop continuation condition | Any node type | while (stock > 0) {} | whileBlock wb where wb.condition contain binaryOperation bo where bo.lhs.name == "stock"; |
| body | Loop execution code block | body node | while (stock >0) { stock--; } | whileBlock wb where wb.body contain unaryOperation; |
| body.statementNum | Number of statements in loop body | Numeric | while (stock>0) { stock--; print(stock); } | whileBlock wb where wb.body.statementNum == 2; |
| firstStatement | First statement in loop block | Any node type | while (stock>0) { stock--; print(stock); } | whileBlock wb where wb.firstStatement contain unaryOperation; |
| lastStatement | Last statement in loop block | Any node type | while (stock>0) { stock--; print(stock); } | whileBlock wb where wb.lastStatement contain functionCall; |
For Loop Block (forBlock)
Sample code:
for (int prodIdx = 0; prodIdx < productList.size(); prodIdx++) {
processProduct(productList.get(prodIdx));
}
Node attributes:
| Name | Description | Value Type | Sample | DSL Rule |
|---|---|---|---|---|
| initialization | Loop variable enitialization | variableDeclaration, variableAccess node | for (int prodIdx =0; ...) {} | forBlock fb where fb.initialization.name == "prodIdx"; |
| condition | Loop continuation condition | binaryOperation node | for (...; prodIdx < productList.size(); ...) {} | forBlock fb where fb.condition.rhs is functionCall; |
| iteration | Post-iteration update operation | unaryOperation node | for (...; prodIdx++) {} | forBlock fb where fb.iteration.operator == "++"; |
ForEach Loop Block (forEachBlock)
Sample code:
List<String> skuList = List.of("SKU001", "SKU002", "SKU003");
for (String sku : skuList) {
logInventoryLevel(sku);
}
Node attributes:
| Name | Description | Value Type | Sample | DSL Rule |
|---|---|---|---|---|
| variable | Iteration variable | variableDeclaration node | for (String sku : skuList) {} | forEachBlock feb where and(feb.variable is variableDeclaration, feb.variable.name == "sku"); |
| iterable | Collection being iterated over | Any node type | for (String sku : skuList) {} | forEachBlock feb where feb.iterable.name == "skuList"; |
While Loop Block (whileBlock)
Sample code:
int stock = 100;
while (stock > 0) {
stock -= fulfillSingleOrder();
}
Do-While Loop Block (doWhileBlock)
Sample code:
int retryCount = 0;
do {
retryCount++;
sendNotificationAlert();
} while (retryCount < 3 && !alertDelivered);
Node attributes align with the base loop block attribute set.
Exception Handling
Exception handling blocks separate error detection and recovery logic from normal business flow, preventing unexpected program crashes, ensuring proper resource cleanup, and providing actionable error diagnostics. Sample code:
try {
int discount = 100 / eligibleUserCount;
} catch (Exception e) {
throw new RuntimeException("Failed to calculate user discount", e);
} finally {
clearTemporaryCalculationData();
}
Exception Block (exceptionBlock)
Covers tryBlock, catchBlock, and finallyBlock components.
Node attributes:
| Name | Description | Value Type | Sample | DSL Rule |
|---|---|---|---|---|
| tryBlock | Code block where exceptions may be thrown | tryBlock node | try { int discount = 100 / eligibleUserCount; } | exceptionBlock eb where eb.tryBlock contain variableDeclaration; |
| catchBlocks | Collection of catch blocks for handling different exception types | List of catchBlock nodes | catch (Exception e) { throw new RuntimeException(e); } | exceptionBlock eb where eb.catchBlocks contain cb where cb contain throwStatement; |
| finallyBlock | Code guaranteed to execute regardless of exception state | finallyBlock node | finally { clearTempData(); } | exceptionBlock eb where eb.finallyBlock contain functionCall fc where fc.name == "clearTemporaryCalculationData"; |
Catch Block (catchBlock)
Node attributes:
| Name | Description | Value Type | Sample | DSL Rule |
|---|---|---|---|---|
| parameters | List of exception parameters declared for the catch block | Node list | catch (Exception e) {} | catchBlock cb where cb.parameters contain p where p.name == "e"; |
Try-With-Resources Block (tryWithResources)
Auto-closes declared resources after execution to prevent resource leaks, no manual cleanup required. Sample code:
try (FileReader fr = new FileReader("app-config.properties"); BufferedReader br = new BufferedReader(fr)) {
loadApplicationConfig(br);
} catch (FileNotFoundException fnfe) {
logger.error("Configuration file not found", fnfe);
} catch (IOException ioe) {
logger.error("Failed to read configuration file", ioe);
}
Node attributes:
| Name | Description | Value Type | Sample | DSL Rule |
|---|---|---|---|---|
| tryBlock | Main execution code block | tryBlock node | try (...) { loadConfig(br); } | tryWithResources twr where twr.tryBlock contain functionCall; |
| catchBlocks | Collection of exception handling blocks | List of catchBlock nodes | catch (FileNotFoundException fnfe) {} | tryWithResources twr where twr.catchBlocks contain cb where cb contain functionCall fc where fc.name == "error"; |
| finallyBlock | Optional final execution block | finallyBlock node | tryWithResources twr where twr.finallyBlock is not null; |
|
| resources | Collection of auto-closeable resources declared in the try header | List of statement nodes | try (FileReader fr = new FileReader("config.properties")) {} | tryWithResources twr where twr.resources contain re where re contain functionCall fc where fc.name == "FileReader"; |
Static Block (staticBlock)
Static initialization blocks run once when a class is first loaded, before any instance creation or static method invocation, used for static variable initialization, one-time resource loading, class-level configuration setup, and static constant assignment. Sample code:
static {
MAX_RETRY_ATTEMPTS = 5;
loadDefaultConfiguration();
}
DSL rule sample:
staticBlock sb where sb contain variableDeclaration vd where vd.name == "MAX_RETRY_ATTEMPTS";
Synchronized Block (synchronizedBlock)
Synchronized blocks enforce thread safety for shared resource access in multi-threaded environments, ensuring atomicity of operations, preventing race conditions, implementing mutual exclusion, and maintaining data consistency. Sample code:
// Object lock for instance-level resource protection
synchronized (inventoryLock) {
updateStockLevel(skuId, adjustedQuantity);
}
// Class lock for global resource protection
synchronized (OrderService.class) {
return generateUniqueOrderId();
}
Node attributes:
| Name | Description | Value Typpe | Sample | DSL Rule |
|---|---|---|---|---|
| lock | Monitor object used for synchronization | Any node type | synchronized (inventoryLock) {} | synchronizedBlock synb where synb.lock contain variableAccess va where va.name == "inventoryLock"; |
| body | Code block protected by the synchronization lock | block node | synchronized (inventoryLock) { updateStockLevel(...); } | synchronizedBlock synb where synb.body contain functionCall fc where fc.name == "updateStockLevel"; |
| body.statementNum | Number of statements in the synchronized block | Numeric | synchronized (inventoryLock) { updateStockLevel(skuId, qty); } | synchronizedBlock synb where synb.body.statementNum == 1; |
| firstStatement | First statement in the synchronized block | Any node type | synchronizedBlock synb where synb.firstStatement contain functionCall; |
|
| lastStatement | Last statement in the synchronized block | Any node type | synchronizedBlock synb where synb.lastStatement contain returnStatement; |