Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | 2514x | import type ISourceSpan from "../../../../types/ISourceSpan";
import type TSymbolKindCNext from "../../../../types/symbol-kinds/TSymbolKindCNext";
import type TVisibility from "../../../../types/TVisibility";
import ESourceLanguage from "../../../../utils/types/ESourceLanguage";
import ParserUtils from "../../../../utils/ParserUtils";
import ScopeUtils from "../../../../utils/ScopeUtils";
interface IMemberSymbolInput<K extends TSymbolKindCNext> {
readonly kind: K;
/** The member's own name, as the source spells it. */
readonly name: string;
/**
* The DECLARING TYPE's `cnxScopedName` -- `EColor`, `SPoint`, or
* `Motor.EMode` for a scope-declared one. Not the enclosing scope's path:
* a member hangs off its type, not off the scope the type sits in.
*/
readonly parentScopedName: string;
/** The member's own parse context, so it gets its own span. */
readonly memberCtx: {
start?: { line?: number; column?: number } | null;
stop?: {
line?: number;
column?: number;
text?: string | null;
start?: number;
stop?: number;
} | null;
};
/**
* The declaring type's span, used only when the member context has no start
* token. See `ParserUtils.getSpanOr` for why inheriting beats `0:0`.
*/
readonly parentSpan: ISourceSpan;
readonly sourceFile: string;
/** The declaring type's visibility, which the member inherits. */
readonly visibility: TVisibility;
}
/**
* The `IBaseSymbol` half of a member symbol, built one way for all four kinds.
*
* Enum members, struct fields, bitmap fields and register members became
* symbols in #1318, and each collector would otherwise spell the same nine
* fields itself. Four copies of "how is a member identified and positioned" is
* the duplicate code path CLAUDE.md calls the project's worst anti-pattern:
* they would agree today and diverge the first time one is edited, and the
* divergence would be invisible because each collector's tests only ever look
* at its own kind.
*
* The two facts it owns:
*
* - **Position is the MEMBER's.** Handing a member its parent's span is the
* defect this card exists to remove -- `parseWithSymbols` did exactly that
* for enum members, so an IDE jumping to `Color.Blue` landed on `enum Color`.
* - **Identity comes from `ScopeUtils.identityOf`,** never a hand-built join
* (#1285). For `enum_member` the result is real generated C -- `EColor__RED`,
* `Motor__EMode__HIGH`, both in committed `.expected.h` fixtures. For the
* other three it is an INDEX KEY ONLY: a struct field is emitted `p.x`, so
* `SPoint__x` distinguishes it from `SOther__x` in the table and appears in
* no generated file. See `IBaseSymbol.fullyQualifiedCName`.
*/
class MemberSymbolBase {
static of<K extends TSymbolKindCNext>(
input: IMemberSymbolInput<K>,
): {
kind: K;
name: string;
scopePath: string;
fullyQualifiedCName: string;
cnxScopedName: string;
sourceFile: string;
span: ISourceSpan;
sourceLanguage: ESourceLanguage;
visibility: TVisibility;
} {
return {
kind: input.kind,
name: input.name,
scopePath: input.parentScopedName,
...ScopeUtils.identityOf({
name: input.name,
scopePath: input.parentScopedName,
}),
sourceFile: input.sourceFile,
// Same fallback the C path uses, through the same function: a member
// with no start token inherits its parent's span rather than
// reporting 0:0, which is both the top of the file and
// indistinguishable from UNSET_SOURCE_SPAN (#1318 review).
span: ParserUtils.getSpanOr(input.memberCtx, input.parentSpan),
sourceLanguage: ESourceLanguage.CNext,
visibility: input.visibility,
};
}
}
export default MemberSymbolBase;
|