Skip to content

Commit b228958

Browse files
authored
Merge pull request #153 from ALCops/docs/pc0038-fc0007-lc0089-fielderror
docs(PC0038, FC0007, LC0089): document FieldError as a flow terminator
2 parents c08cd99 + 5fc33e2 commit b228958

3 files changed

Lines changed: 18 additions & 6 deletions

File tree

content/docs/analyzers/FormattingCop/FC0007.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ linkTitle = 'FC0007'
1010
ignoreObsolete = true
1111
+++
1212

13-
Multi-line control-flow blocks (`if`, `case`, `repeat`, `while`, `for`, `foreach`) and scope-leaving statements (`exit`, built-in `Error(...)`) read more clearly when they are visually separated from surrounding code by a blank line. The rule reports the exact spot where a separator is missing so it can be inserted with a single keystroke, without touching the logic.
13+
Multi-line control-flow blocks (`if`, `case`, `repeat`, `while`, `for`, `foreach`) and scope-leaving statements (`exit`, built-in `Error(...)` and `FieldError(...)`) read more clearly when they are visually separated from surrounding code by a blank line. The rule reports the exact spot where a separator is missing so it can be inserted with a single keystroke, without touching the logic.
1414

1515
FC0007 is **disabled by default** and fully configurable. Enable it in your project's `.ruleset.json` (or via `AL: Configure ruleset`) and, optionally, tune the individual checks in `alcops.json`.
1616

@@ -70,7 +70,7 @@ The rule runs four independent checks. Each check can be toggled or narrowed via
7070
|---|---|---|
7171
| Blank line **before** a control-flow block | A multi-line `if`, `case`, `repeat`, `while`, `for`, or `foreach` immediately follows another statement in the same block. | `ControlFlowBefore` |
7272
| Blank line **after** a control-flow block | A non-control-flow statement immediately follows the closing `end` (or `until`) of a multi-line control-flow block. | `ControlFlowAfter` |
73-
| Blank line before a **scope-leaving** statement | `exit`, built-in `Error(...)`, or both follow a sibling statement in the same statement list without a whitespace-only line between them. | `ScopeLeavingMode` |
73+
| Blank line before a **scope-leaving** statement | `exit`, a built-in `Error(...)` / `FieldError(...)` call, or both follow a sibling statement in the same statement list without a whitespace-only line between them. | `ScopeLeavingMode` |
7474
| Blank line before **`else`** in an `if ... end else` construct | The closing `end` and the `else` keyword sit on adjacent lines instead of being separated by a blank line. Opt-in. | `ElseChainBeforeMode` |
7575

7676
Single-line control-flow statements (e.g. `if Flag then Message('x');` on one line) are excluded from the *before* / *after* checks by default. Include them with `OneLinerMode`.
@@ -97,7 +97,7 @@ exit; // OK: the empty line above still counts as a separa
9797

9898
- The symbol is obsolete
9999
- Adjacent case branches inside a `case` statement (the check operates on the surrounding block, not on branches)
100-
- An `exit` or `Error(...)` used directly as a `then` / `else` branch (the containing `if` is governed by the control-flow settings)
100+
- An `exit`, `Error(...)` or `FieldError(...)` used directly as a `then` / `else` branch (the containing `if` is governed by the control-flow settings)
101101
- Any statement immediately after `begin` or immediately before `end` (the block braces already act as separators)
102102

103103
### Configuration
@@ -120,7 +120,7 @@ All settings live under a single `StatementBlockSpacing` object in `alcops.json`
120120
|---|---|---|---|---|
121121
| `ControlFlowBefore` | boolean | `true` | `true` / `false` | Require a blank line before a multi-line control-flow block when it follows another statement in the same block. |
122122
| `ControlFlowAfter` | boolean | `true` | `true` / `false` | Require a blank line after a multi-line control-flow block when a non-control-flow statement follows it directly. |
123-
| `ScopeLeavingMode` | string | `"ExitAndError"` | `"Off"`, `"ExitOnly"`, `"ErrorOnly"`, `"ExitAndError"` | Which scope-leaving statements require a preceding blank line. |
123+
| `ScopeLeavingMode` | string | `"ExitAndError"` | `"Off"`, `"ExitOnly"`, `"ErrorOnly"`, `"ExitAndError"` | Which scope-leaving statements require a preceding blank line. `ErrorOnly` and `ExitAndError` cover the built-in `Error(...)` as well as `Record.FieldError(...)` / `FieldRef.FieldError(...)`. |
124124
| `ElseChainBeforeMode` | string | `"Off"` | `"Off"`, `"RequireBlank"` | Whether the `else` keyword of an `if ... end else` construct must sit on its own after a blank line. |
125125
| `OneLinerMode` | string | `"None"` | `"None"`, `"All"` | Whether single-line control-flow statements participate in the `ControlFlowBefore` / `ControlFlowAfter` checks. |
126126

@@ -142,7 +142,7 @@ Turn every check off and re-enable individual ones:
142142
}
143143
```
144144

145-
With this configuration the rule flags only the space before a multi-line block and the space before an `Error(...)` call; `exit` statements, trailing blanks and one-liners are ignored.
145+
With this configuration the rule flags only the space before a multi-line block and the space before an `Error(...)` or `FieldError(...)` call; `exit` statements, trailing blanks and one-liners are ignored.
146146

147147
#### Enforcing blank line before `else`
148148

content/docs/analyzers/LinterCop/LC0089.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ begin
4848
end;
4949
{{< /highlight >}}
5050

51+
A guard clause is an `if` whose only statement leaves the current flow: `exit`, `break`, `continue`, `CurrReport.Skip()` / `CurrReport.Break()` / `CurrReport.Quit()` (and the `CurrXMLport` equivalents), or a call to a built-in method that never returns — `Error(...)`, `Record.FieldError(...)` or `FieldRef.FieldError(...)`. A user-defined procedure that happens to be named `Error` or `FieldError` is a normal call and keeps its increment.
52+
5153
For the full scoring model — how nesting penalties, logical operators, recursion, and compensating usages like `else if` are calculated — see [LC0090](../lc0090/).
5254

5355
### Increment diagnostics

content/docs/analyzers/PlatformCop/PC0038.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Triggers are intentionally excluded from this rule, even when they declare a ret
5050

5151
### Exception
5252

53-
Paths that end with `Error(...)` are accepted:
53+
Paths that end with a built-in call that never returns — `Error(...)`, `Record.FieldError(...)` or `FieldRef.FieldError(...)` are accepted:
5454

5555
{{< highlight al >}}
5656
procedure GetAmount(IncludeVat: Boolean): Decimal
@@ -60,8 +60,18 @@ begin
6060
else
6161
Error('Prices without VAT are not supported.');
6262
end;
63+
64+
procedure GetUnitPrice(Item: Record Item): Decimal
65+
begin
66+
if Item."Unit Price" > 0 then
67+
exit(Item."Unit Price")
68+
else
69+
Item.FieldError("Unit Price", 'must be positive.');
70+
end;
6371
{{< /highlight >}}
6472

73+
Only the built-in methods qualify; a user-defined procedure that happens to be named `Error` or `FieldError` does not terminate the path.
74+
6575
A named return variable passed to a `var` parameter, or used as the receiver of a call, counts as assigned:
6676

6777
{{< highlight al >}}

0 commit comments

Comments
 (0)