sysml-v2-lsp 0.38.0 → 0.39.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/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.39.0]
6
+
7
+ ### Fixed
8
+
9
+ - A short name that clashes with a sibling's name or short name (`part def <A> Alpha; part def A;`) is reported as `ambiguous-namespace-name` (KerML 7.2.5.2), and a reference by the name they clash on (`A`) is left unresolved rather than taken for either.
10
+ - Keep ambiguous names unresolved in navigation, hover, references, rename,
11
+ linked editing and hierarchy preparation, including qualified and feature paths.
12
+ Retain every conflicting declaration when both names of an element clash.
13
+
5
14
  ## [0.38.0]
6
15
 
7
16
  ### Added
@@ -136447,12 +136447,19 @@ ${JSON.stringify(message, null, 4)}`);
136447
136447
  function findConflictedQualifiedNames(allSymbols) {
136448
136448
  return groupConflicts(allSymbols.filter((s) => s.qualifiedName !== void 0), (s) => s.qualifiedName);
136449
136449
  }
136450
+ function memberNamesOf(symbol) {
136451
+ return symbol.shortName && symbol.shortName !== symbol.name ? [symbol.name, symbol.shortName] : [symbol.name];
136452
+ }
136450
136453
  function findConflictingDeclarations(allSymbols) {
136451
136454
  const conflicting = /* @__PURE__ */ new Map();
136452
136455
  const add = (groups) => {
136453
- for (const group of groups.values()) for (const s of group) conflicting.set(s, group);
136456
+ for (const group of groups) {
136457
+ for (const s of group) {
136458
+ conflicting.set(s, [.../* @__PURE__ */ new Set([...conflicting.get(s) ?? [], ...group])]);
136459
+ }
136460
+ }
136454
136461
  };
136455
- add(findConflictedQualifiedNames(allSymbols));
136462
+ add(findConflictedQualifiedNames(allSymbols).values());
136456
136463
  const membersOfAnonymous = allSymbols.filter((s) => s.qualifiedName === void 0 && !isAnonymous(s) && s.parentId !== void 0);
136457
136464
  const byOwner = /* @__PURE__ */ new Map();
136458
136465
  for (const s of membersOfAnonymous) {
@@ -136460,13 +136467,33 @@ ${JSON.stringify(message, null, 4)}`);
136460
136467
  list.push(s);
136461
136468
  byOwner.set(s.parentId, list);
136462
136469
  }
136463
- for (const members of byOwner.values()) add(groupConflicts(members, (s) => s.name));
136470
+ for (const members of byOwner.values()) add(groupConflicts(members, (s) => s.name).values());
136471
+ add([...findConflictingShortNames(allSymbols).values()].map((group) => group.symbols));
136464
136472
  return conflicting;
136465
136473
  }
136474
+ function findConflictingShortNames(allSymbols) {
136475
+ const byId = new Map(allSymbols.map((s) => [s.symbolId, s]));
136476
+ const entries = [];
136477
+ const keysWithShortName = /* @__PURE__ */ new Set();
136478
+ for (const s of allSymbols) {
136479
+ if (isAnonymous(s)) continue;
136480
+ const owner = s.parentId ? byId.get(s.parentId) : void 0;
136481
+ const namespace = owner === void 0 ? "q:" : owner.qualifiedName !== void 0 ? `q:${owner.qualifiedName}` : `id:${owner.symbolId}`;
136482
+ for (const name of memberNamesOf(s)) {
136483
+ const key = `${namespace}\0${name}`;
136484
+ entries.push({ symbol: s, key });
136485
+ if (name === s.shortName) keysWithShortName.add(key);
136486
+ }
136487
+ }
136488
+ const groups = groupKeyedConflicts(entries.filter((e) => keysWithShortName.has(e.key)));
136489
+ return new Map([...groups].map(([key, symbols]) => [key, { name: key.slice(key.indexOf("\0") + 1), symbols }]));
136490
+ }
136466
136491
  function groupConflicts(symbols, keyOf) {
136492
+ return groupKeyedConflicts(symbols.map((symbol) => ({ symbol, key: keyOf(symbol) })));
136493
+ }
136494
+ function groupKeyedConflicts(entries) {
136467
136495
  const byKeyAndKind = /* @__PURE__ */ new Map();
136468
- for (const s of symbols) {
136469
- const key = keyOf(s);
136496
+ for (const { symbol: s, key } of entries) {
136470
136497
  let byKind = byKeyAndKind.get(key);
136471
136498
  if (!byKind) {
136472
136499
  byKind = /* @__PURE__ */ new Map();
@@ -136538,7 +136565,13 @@ ${JSON.stringify(message, null, 4)}`);
136538
136565
  for (const s of allSymbols) {
136539
136566
  byId.set(s.symbolId, s);
136540
136567
  }
136541
- const indexes = { byName, byParent, byQualifiedName, byId, definitionsByName, portsByName };
136568
+ const clashingShortNames = /* @__PURE__ */ new Map();
136569
+ for (const { name, symbols } of findConflictingShortNames(allSymbols).values()) {
136570
+ const clashing = clashingShortNames.get(name) ?? /* @__PURE__ */ new Set();
136571
+ for (const s of symbols) clashing.add(s);
136572
+ clashingShortNames.set(name, clashing);
136573
+ }
136574
+ const indexes = { byName, byParent, byQualifiedName, byId, definitionsByName, portsByName, clashingShortNames };
136542
136575
  for (const s of allSymbols) {
136543
136576
  if (isAnonymous(s)) continue;
136544
136577
  const nameList = byName.get(s.name) ?? [];
@@ -136627,6 +136660,16 @@ ${JSON.stringify(message, null, 4)}`);
136627
136660
  resolveNameIn(namespace, name, indexes) {
136628
136661
  return this.resolveQualifiedNameFrom(namespace ? namespaceKeyOf(namespace) : "", name, indexes);
136629
136662
  }
136663
+ /** Resolve an editor reference without losing the reason a name is unresolved. */
136664
+ resolveReferenceIn(namespace, name, indexes) {
136665
+ return this.resolveQualifiedReferenceFrom(namespace ? namespaceKeyOf(namespace) : "", name, indexes);
136666
+ }
136667
+ /** Resolve a public qualified or feature-path member, without enclosing-scope fallback. */
136668
+ resolveMemberReference(owner, name, indexes) {
136669
+ const members = this.getResolvedMembers(namespaceKeyOf(owner), indexes).get(name);
136670
+ if (members && this.isAmbiguous(name, members, indexes)) return { ambiguous: true };
136671
+ return this.referenceTo(members?.find((member) => member.visibility === "public")?.symbol, indexes);
136672
+ }
136630
136673
  /**
136631
136674
  * Resolve a (possibly qualified) name to its symbol per §7.5.1, searching
136632
136675
  * outward from namespace `start` and its enclosing namespaces (its own resolved
@@ -136638,28 +136681,48 @@ ${JSON.stringify(message, null, 4)}`);
136638
136681
  * its own enclosing package already imported, per §7.5.1/§7.5.3).
136639
136682
  */
136640
136683
  resolveQualifiedNameFrom(start, name, indexes) {
136684
+ return this.resolveQualifiedReferenceFrom(start, name, indexes).symbol;
136685
+ }
136686
+ resolveQualifiedReferenceFrom(start, name, indexes) {
136641
136687
  const [first, ...rest] = splitQualifiedName(name);
136642
136688
  let resolved;
136643
136689
  for (const ancestor of this.namespaceAncestorsOf(start, indexes)) {
136644
136690
  const candidates = this.getResolvedMembers(ancestor, indexes).get(first);
136645
136691
  if (candidates && candidates.length > 0) {
136692
+ if (this.isAmbiguous(first, candidates, indexes)) return { ambiguous: true };
136646
136693
  resolved = candidates[0].symbol;
136647
136694
  break;
136648
136695
  }
136649
136696
  }
136650
- if (resolved === void 0) return void 0;
136697
+ if (resolved === void 0) return { ambiguous: false };
136651
136698
  const isWithinStart = (namespace) => this.namespaceAncestorsOf(start, indexes).has(namespace);
136652
136699
  for (const segment of rest) {
136653
136700
  const owner = resolved;
136654
136701
  const ownerKey = namespaceKeyOf(owner);
136655
136702
  const members = this.getResolvedMembers(ownerKey, indexes).get(segment);
136703
+ if (members && this.isAmbiguous(segment, members, indexes)) return { ambiguous: true };
136656
136704
  const visibleMember = members?.find(
136657
136705
  (m2) => m2.visibility === "public" || isWithinStart(ownerKey) || m2.visibility === "protected" && this.isProtectedVisibleFrom(start, owner, indexes)
136658
136706
  );
136659
- if (!visibleMember) return void 0;
136707
+ if (!visibleMember) return { ambiguous: false };
136660
136708
  resolved = visibleMember.symbol;
136661
136709
  }
136662
- return resolved.qualifiedName !== void 0 ? indexes.byQualifiedName.get(resolved.qualifiedName) : resolved;
136710
+ return this.referenceTo(resolved, indexes);
136711
+ }
136712
+ referenceTo(resolved, indexes) {
136713
+ if (!resolved) return { ambiguous: false };
136714
+ const symbol = resolved.qualifiedName !== void 0 ? indexes.byQualifiedName.get(resolved.qualifiedName) : resolved;
136715
+ return { symbol, ambiguous: symbol === void 0 };
136716
+ }
136717
+ /**
136718
+ * Whether `name` names more than one of `candidates` that clash on it
136719
+ * through a short name (`SymbolIndexes.clashingShortNames`), so it can't
136720
+ * be resolved to either (KerML 7.2.5.2). Like a conflicted qualifiedName,
136721
+ * it doesn't fall through to an enclosing namespace's member of that name.
136722
+ */
136723
+ isAmbiguous(name, candidates, indexes) {
136724
+ const clashing = indexes.clashingShortNames.get(name);
136725
+ return clashing !== void 0 && candidates.filter((c) => clashing.has(c.symbol)).length > 1;
136663
136726
  }
136664
136727
  /**
136665
136728
  * §7.5.3's protected-import exception: "A visibility of protected is the
@@ -139365,9 +139428,11 @@ ${childIndent}item def ${sourceName};
139365
139428
  if (target && !path.qualifiedNames.some((name) => name.segments.some((segment) => segment.name === target.name || segment.name === target.shortName))) continue;
139366
139429
  const namespace = namespaces.find((ns) => ns.body < path.start && path.end <= ns.end);
139367
139430
  let receiver;
139431
+ let receiverAmbiguous = false;
139368
139432
  for (let group = 0; group < path.qualifiedNames.length; group++) {
139369
139433
  const qualified = path.qualifiedNames[group];
139370
139434
  let resolved;
139435
+ let ambiguous = false;
139371
139436
  for (let index2 = 0; index2 < qualified.segments.length; index2++) {
139372
139437
  const segment = qualified.segments[index2];
139373
139438
  const range = import_node3.Range.create(doc.positionAt(segment.start), doc.positionAt(segment.end));
@@ -139376,17 +139441,27 @@ ${childIndent}item def ${sourceName};
139376
139441
  while (before >= 0 && /\s/.test(text[before])) before--;
139377
139442
  while (after < text.length && /\s/.test(text[after])) after++;
139378
139443
  const declaration = symbols.find((symbol) => !isAnonymous(symbol) && (symbol.selectionRange.start.line === range.start.line && symbol.selectionRange.start.character === range.start.character && symbol.selectionRange.end.character === range.end.character || symbol.shortName === segment.name && text[before] === "<" && text[after] === ">" && doc.offsetAt(symbol.range.start) <= segment.start && segment.end < doc.offsetAt(symbol.selectionRange.start)));
139379
- if (declaration) resolved = declaration;
139380
- else if (index2 > 0) {
139381
- resolved = resolved ? this.resolver.getResolvedMembers(namespaceKeyOf(resolved), this.indexes).get(segment.name)?.find((entry) => entry.visibility === "public")?.symbol : void 0;
139444
+ if (declaration) {
139445
+ resolved = declaration;
139446
+ ambiguous = false;
139447
+ } else if (index2 > 0) {
139448
+ if (resolved) {
139449
+ const result = this.resolver.resolveMemberReference(resolved, segment.name, this.indexes);
139450
+ resolved = result.symbol;
139451
+ ambiguous = result.ambiguous;
139452
+ }
139382
139453
  } else if (group > 0) {
139383
- resolved = receiver ? this.resolveFeature(receiver, segment.name) : void 0;
139454
+ const result = receiver ? this.resolveFeature(receiver, segment.name) : { ambiguous: receiverAmbiguous };
139455
+ resolved = result.symbol;
139456
+ ambiguous = result.ambiguous;
139384
139457
  } else {
139385
- resolved = this.resolver.resolveNameIn(
139458
+ const result = this.resolver.resolveReferenceIn(
139386
139459
  namespace?.symbol,
139387
139460
  joinQualifiedName([segment.name]),
139388
139461
  this.indexes
139389
139462
  );
139463
+ resolved = result.symbol;
139464
+ ambiguous = result.ambiguous;
139390
139465
  }
139391
139466
  if (cursor !== void 0 && (cursor < segment.start || cursor > segment.end)) continue;
139392
139467
  if (target && segment.name !== target.name && segment.name !== target.shortName) continue;
@@ -139396,10 +139471,12 @@ ${childIndent}item def ${sourceName};
139396
139471
  name: segment.name,
139397
139472
  qualifiedName: index2 === qualified.segments.length - 1 ? qualified.name : segment.name,
139398
139473
  symbol: resolved,
139399
- isDeclaration: declaration !== void 0
139474
+ isDeclaration: declaration !== void 0,
139475
+ isAmbiguous: ambiguous
139400
139476
  });
139401
139477
  }
139402
139478
  receiver = resolved;
139479
+ receiverAmbiguous = ambiguous;
139403
139480
  }
139404
139481
  }
139405
139482
  return refs;
@@ -139411,14 +139488,14 @@ ${childIndent}item def ${sourceName};
139411
139488
  const owner = queue[index2];
139412
139489
  if (visited.has(owner)) continue;
139413
139490
  visited.add(owner);
139414
- const member = this.resolver.getResolvedMembers(namespaceKeyOf(owner), this.indexes).get(name)?.find((entry) => entry.visibility === "public")?.symbol;
139415
- if (member) return member;
139491
+ const member = this.resolver.resolveMemberReference(owner, name, this.indexes);
139492
+ if (member.symbol || member.ambiguous) return member;
139416
139493
  for (const typeName of owner.typeNames) {
139417
139494
  const type = this.resolver.resolveNameFrom(owner, typeName, this.indexes);
139418
139495
  if (type && !visited.has(type)) queue.push(type);
139419
139496
  }
139420
139497
  }
139421
- return void 0;
139498
+ return { ambiguous: false };
139422
139499
  }
139423
139500
  };
139424
139501
 
@@ -139435,6 +139512,7 @@ ${childIndent}item def ${sourceName};
139435
139512
  }
139436
139513
  const wsSymbolTable = this.documentManager.getWorkspaceSymbolTable();
139437
139514
  const reference = new NameReferences(this.documentManager).at(params.textDocument.uri, params.position);
139515
+ if (reference?.isAmbiguous) return null;
139438
139516
  if (reference?.symbol && !reference.isDeclaration) {
139439
139517
  return { uri: reference.symbol.uri, range: reference.symbol.selectionRange };
139440
139518
  }
@@ -140049,6 +140127,7 @@ ${childIndent}item def ${sourceName};
140049
140127
  }
140050
140128
  const text = this.documentManager.getText(params.textDocument.uri);
140051
140129
  const reference = new NameReferences(this.documentManager).at(params.textDocument.uri, params.position);
140130
+ if (reference?.isAmbiguous) return null;
140052
140131
  const word = reference?.qualifiedName ?? (text ? this.getWordAtPosition(text, params.position.line, params.position.character) : void 0);
140053
140132
  if (word && word.includes("::") && !reference?.symbol) {
140054
140133
  const libHover = this.buildLibraryHover(word);
@@ -159214,12 +159214,19 @@ var MAX_NAMESPACE_NESTING_DEPTH = 64;
159214
159214
  function findConflictedQualifiedNames(allSymbols) {
159215
159215
  return groupConflicts(allSymbols.filter((s) => s.qualifiedName !== void 0), (s) => s.qualifiedName);
159216
159216
  }
159217
+ function memberNamesOf(symbol2) {
159218
+ return symbol2.shortName && symbol2.shortName !== symbol2.name ? [symbol2.name, symbol2.shortName] : [symbol2.name];
159219
+ }
159217
159220
  function findConflictingDeclarations(allSymbols) {
159218
159221
  const conflicting = /* @__PURE__ */ new Map();
159219
159222
  const add = (groups) => {
159220
- for (const group of groups.values()) for (const s of group) conflicting.set(s, group);
159223
+ for (const group of groups) {
159224
+ for (const s of group) {
159225
+ conflicting.set(s, [.../* @__PURE__ */ new Set([...conflicting.get(s) ?? [], ...group])]);
159226
+ }
159227
+ }
159221
159228
  };
159222
- add(findConflictedQualifiedNames(allSymbols));
159229
+ add(findConflictedQualifiedNames(allSymbols).values());
159223
159230
  const membersOfAnonymous = allSymbols.filter((s) => s.qualifiedName === void 0 && !isAnonymous(s) && s.parentId !== void 0);
159224
159231
  const byOwner = /* @__PURE__ */ new Map();
159225
159232
  for (const s of membersOfAnonymous) {
@@ -159227,13 +159234,33 @@ function findConflictingDeclarations(allSymbols) {
159227
159234
  list.push(s);
159228
159235
  byOwner.set(s.parentId, list);
159229
159236
  }
159230
- for (const members2 of byOwner.values()) add(groupConflicts(members2, (s) => s.name));
159237
+ for (const members2 of byOwner.values()) add(groupConflicts(members2, (s) => s.name).values());
159238
+ add([...findConflictingShortNames(allSymbols).values()].map((group) => group.symbols));
159231
159239
  return conflicting;
159232
159240
  }
159241
+ function findConflictingShortNames(allSymbols) {
159242
+ const byId = new Map(allSymbols.map((s) => [s.symbolId, s]));
159243
+ const entries = [];
159244
+ const keysWithShortName = /* @__PURE__ */ new Set();
159245
+ for (const s of allSymbols) {
159246
+ if (isAnonymous(s)) continue;
159247
+ const owner = s.parentId ? byId.get(s.parentId) : void 0;
159248
+ const namespace = owner === void 0 ? "q:" : owner.qualifiedName !== void 0 ? `q:${owner.qualifiedName}` : `id:${owner.symbolId}`;
159249
+ for (const name of memberNamesOf(s)) {
159250
+ const key = `${namespace}\0${name}`;
159251
+ entries.push({ symbol: s, key });
159252
+ if (name === s.shortName) keysWithShortName.add(key);
159253
+ }
159254
+ }
159255
+ const groups = groupKeyedConflicts(entries.filter((e) => keysWithShortName.has(e.key)));
159256
+ return new Map([...groups].map(([key, symbols]) => [key, { name: key.slice(key.indexOf("\0") + 1), symbols }]));
159257
+ }
159233
159258
  function groupConflicts(symbols, keyOf) {
159259
+ return groupKeyedConflicts(symbols.map((symbol2) => ({ symbol: symbol2, key: keyOf(symbol2) })));
159260
+ }
159261
+ function groupKeyedConflicts(entries) {
159234
159262
  const byKeyAndKind = /* @__PURE__ */ new Map();
159235
- for (const s of symbols) {
159236
- const key = keyOf(s);
159263
+ for (const { symbol: s, key } of entries) {
159237
159264
  let byKind = byKeyAndKind.get(key);
159238
159265
  if (!byKind) {
159239
159266
  byKind = /* @__PURE__ */ new Map();
@@ -159305,7 +159332,13 @@ function buildSymbolIndexes(allSymbols) {
159305
159332
  for (const s of allSymbols) {
159306
159333
  byId.set(s.symbolId, s);
159307
159334
  }
159308
- const indexes = { byName, byParent, byQualifiedName, byId, definitionsByName, portsByName };
159335
+ const clashingShortNames = /* @__PURE__ */ new Map();
159336
+ for (const { name, symbols } of findConflictingShortNames(allSymbols).values()) {
159337
+ const clashing = clashingShortNames.get(name) ?? /* @__PURE__ */ new Set();
159338
+ for (const s of symbols) clashing.add(s);
159339
+ clashingShortNames.set(name, clashing);
159340
+ }
159341
+ const indexes = { byName, byParent, byQualifiedName, byId, definitionsByName, portsByName, clashingShortNames };
159309
159342
  for (const s of allSymbols) {
159310
159343
  if (isAnonymous(s)) continue;
159311
159344
  const nameList = byName.get(s.name) ?? [];
@@ -159394,6 +159427,16 @@ var NamespaceResolver = class {
159394
159427
  resolveNameIn(namespace, name, indexes) {
159395
159428
  return this.resolveQualifiedNameFrom(namespace ? namespaceKeyOf(namespace) : "", name, indexes);
159396
159429
  }
159430
+ /** Resolve an editor reference without losing the reason a name is unresolved. */
159431
+ resolveReferenceIn(namespace, name, indexes) {
159432
+ return this.resolveQualifiedReferenceFrom(namespace ? namespaceKeyOf(namespace) : "", name, indexes);
159433
+ }
159434
+ /** Resolve a public qualified or feature-path member, without enclosing-scope fallback. */
159435
+ resolveMemberReference(owner, name, indexes) {
159436
+ const members2 = this.getResolvedMembers(namespaceKeyOf(owner), indexes).get(name);
159437
+ if (members2 && this.isAmbiguous(name, members2, indexes)) return { ambiguous: true };
159438
+ return this.referenceTo(members2?.find((member) => member.visibility === "public")?.symbol, indexes);
159439
+ }
159397
159440
  /**
159398
159441
  * Resolve a (possibly qualified) name to its symbol per §7.5.1, searching
159399
159442
  * outward from namespace `start` and its enclosing namespaces (its own resolved
@@ -159405,28 +159448,48 @@ var NamespaceResolver = class {
159405
159448
  * its own enclosing package already imported, per §7.5.1/§7.5.3).
159406
159449
  */
159407
159450
  resolveQualifiedNameFrom(start, name, indexes) {
159451
+ return this.resolveQualifiedReferenceFrom(start, name, indexes).symbol;
159452
+ }
159453
+ resolveQualifiedReferenceFrom(start, name, indexes) {
159408
159454
  const [first, ...rest] = splitQualifiedName(name);
159409
159455
  let resolved;
159410
159456
  for (const ancestor of this.namespaceAncestorsOf(start, indexes)) {
159411
159457
  const candidates = this.getResolvedMembers(ancestor, indexes).get(first);
159412
159458
  if (candidates && candidates.length > 0) {
159459
+ if (this.isAmbiguous(first, candidates, indexes)) return { ambiguous: true };
159413
159460
  resolved = candidates[0].symbol;
159414
159461
  break;
159415
159462
  }
159416
159463
  }
159417
- if (resolved === void 0) return void 0;
159464
+ if (resolved === void 0) return { ambiguous: false };
159418
159465
  const isWithinStart = (namespace) => this.namespaceAncestorsOf(start, indexes).has(namespace);
159419
159466
  for (const segment of rest) {
159420
159467
  const owner = resolved;
159421
159468
  const ownerKey = namespaceKeyOf(owner);
159422
159469
  const members2 = this.getResolvedMembers(ownerKey, indexes).get(segment);
159470
+ if (members2 && this.isAmbiguous(segment, members2, indexes)) return { ambiguous: true };
159423
159471
  const visibleMember = members2?.find(
159424
159472
  (m2) => m2.visibility === "public" || isWithinStart(ownerKey) || m2.visibility === "protected" && this.isProtectedVisibleFrom(start, owner, indexes)
159425
159473
  );
159426
- if (!visibleMember) return void 0;
159474
+ if (!visibleMember) return { ambiguous: false };
159427
159475
  resolved = visibleMember.symbol;
159428
159476
  }
159429
- return resolved.qualifiedName !== void 0 ? indexes.byQualifiedName.get(resolved.qualifiedName) : resolved;
159477
+ return this.referenceTo(resolved, indexes);
159478
+ }
159479
+ referenceTo(resolved, indexes) {
159480
+ if (!resolved) return { ambiguous: false };
159481
+ const symbol2 = resolved.qualifiedName !== void 0 ? indexes.byQualifiedName.get(resolved.qualifiedName) : resolved;
159482
+ return { symbol: symbol2, ambiguous: symbol2 === void 0 };
159483
+ }
159484
+ /**
159485
+ * Whether `name` names more than one of `candidates` that clash on it
159486
+ * through a short name (`SymbolIndexes.clashingShortNames`), so it can't
159487
+ * be resolved to either (KerML 7.2.5.2). Like a conflicted qualifiedName,
159488
+ * it doesn't fall through to an enclosing namespace's member of that name.
159489
+ */
159490
+ isAmbiguous(name, candidates, indexes) {
159491
+ const clashing = indexes.clashingShortNames.get(name);
159492
+ return clashing !== void 0 && candidates.filter((c) => clashing.has(c.symbol)).length > 1;
159430
159493
  }
159431
159494
  /**
159432
159495
  * §7.5.3's protected-import exception: "A visibility of protected is the
@@ -125418,12 +125418,19 @@ var MAX_NAMESPACE_NESTING_DEPTH = 64;
125418
125418
  function findConflictedQualifiedNames(allSymbols) {
125419
125419
  return groupConflicts(allSymbols.filter((s) => s.qualifiedName !== void 0), (s) => s.qualifiedName);
125420
125420
  }
125421
+ function memberNamesOf(symbol) {
125422
+ return symbol.shortName && symbol.shortName !== symbol.name ? [symbol.name, symbol.shortName] : [symbol.name];
125423
+ }
125421
125424
  function findConflictingDeclarations(allSymbols) {
125422
125425
  const conflicting = /* @__PURE__ */ new Map();
125423
125426
  const add = (groups) => {
125424
- for (const group of groups.values()) for (const s of group) conflicting.set(s, group);
125427
+ for (const group of groups) {
125428
+ for (const s of group) {
125429
+ conflicting.set(s, [.../* @__PURE__ */ new Set([...conflicting.get(s) ?? [], ...group])]);
125430
+ }
125431
+ }
125425
125432
  };
125426
- add(findConflictedQualifiedNames(allSymbols));
125433
+ add(findConflictedQualifiedNames(allSymbols).values());
125427
125434
  const membersOfAnonymous = allSymbols.filter((s) => s.qualifiedName === void 0 && !isAnonymous(s) && s.parentId !== void 0);
125428
125435
  const byOwner = /* @__PURE__ */ new Map();
125429
125436
  for (const s of membersOfAnonymous) {
@@ -125431,13 +125438,33 @@ function findConflictingDeclarations(allSymbols) {
125431
125438
  list.push(s);
125432
125439
  byOwner.set(s.parentId, list);
125433
125440
  }
125434
- for (const members of byOwner.values()) add(groupConflicts(members, (s) => s.name));
125441
+ for (const members of byOwner.values()) add(groupConflicts(members, (s) => s.name).values());
125442
+ add([...findConflictingShortNames(allSymbols).values()].map((group) => group.symbols));
125435
125443
  return conflicting;
125436
125444
  }
125445
+ function findConflictingShortNames(allSymbols) {
125446
+ const byId = new Map(allSymbols.map((s) => [s.symbolId, s]));
125447
+ const entries = [];
125448
+ const keysWithShortName = /* @__PURE__ */ new Set();
125449
+ for (const s of allSymbols) {
125450
+ if (isAnonymous(s)) continue;
125451
+ const owner = s.parentId ? byId.get(s.parentId) : void 0;
125452
+ const namespace = owner === void 0 ? "q:" : owner.qualifiedName !== void 0 ? `q:${owner.qualifiedName}` : `id:${owner.symbolId}`;
125453
+ for (const name of memberNamesOf(s)) {
125454
+ const key = `${namespace}\0${name}`;
125455
+ entries.push({ symbol: s, key });
125456
+ if (name === s.shortName) keysWithShortName.add(key);
125457
+ }
125458
+ }
125459
+ const groups = groupKeyedConflicts(entries.filter((e) => keysWithShortName.has(e.key)));
125460
+ return new Map([...groups].map(([key, symbols]) => [key, { name: key.slice(key.indexOf("\0") + 1), symbols }]));
125461
+ }
125437
125462
  function groupConflicts(symbols, keyOf) {
125463
+ return groupKeyedConflicts(symbols.map((symbol) => ({ symbol, key: keyOf(symbol) })));
125464
+ }
125465
+ function groupKeyedConflicts(entries) {
125438
125466
  const byKeyAndKind = /* @__PURE__ */ new Map();
125439
- for (const s of symbols) {
125440
- const key = keyOf(s);
125467
+ for (const { symbol: s, key } of entries) {
125441
125468
  let byKind = byKeyAndKind.get(key);
125442
125469
  if (!byKind) {
125443
125470
  byKind = /* @__PURE__ */ new Map();
@@ -125509,7 +125536,13 @@ function buildSymbolIndexes(allSymbols) {
125509
125536
  for (const s of allSymbols) {
125510
125537
  byId.set(s.symbolId, s);
125511
125538
  }
125512
- const indexes = { byName, byParent, byQualifiedName, byId, definitionsByName, portsByName };
125539
+ const clashingShortNames = /* @__PURE__ */ new Map();
125540
+ for (const { name, symbols } of findConflictingShortNames(allSymbols).values()) {
125541
+ const clashing = clashingShortNames.get(name) ?? /* @__PURE__ */ new Set();
125542
+ for (const s of symbols) clashing.add(s);
125543
+ clashingShortNames.set(name, clashing);
125544
+ }
125545
+ const indexes = { byName, byParent, byQualifiedName, byId, definitionsByName, portsByName, clashingShortNames };
125513
125546
  for (const s of allSymbols) {
125514
125547
  if (isAnonymous(s)) continue;
125515
125548
  const nameList = byName.get(s.name) ?? [];
@@ -125598,6 +125631,16 @@ var NamespaceResolver = class {
125598
125631
  resolveNameIn(namespace, name, indexes) {
125599
125632
  return this.resolveQualifiedNameFrom(namespace ? namespaceKeyOf(namespace) : "", name, indexes);
125600
125633
  }
125634
+ /** Resolve an editor reference without losing the reason a name is unresolved. */
125635
+ resolveReferenceIn(namespace, name, indexes) {
125636
+ return this.resolveQualifiedReferenceFrom(namespace ? namespaceKeyOf(namespace) : "", name, indexes);
125637
+ }
125638
+ /** Resolve a public qualified or feature-path member, without enclosing-scope fallback. */
125639
+ resolveMemberReference(owner, name, indexes) {
125640
+ const members = this.getResolvedMembers(namespaceKeyOf(owner), indexes).get(name);
125641
+ if (members && this.isAmbiguous(name, members, indexes)) return { ambiguous: true };
125642
+ return this.referenceTo(members?.find((member) => member.visibility === "public")?.symbol, indexes);
125643
+ }
125601
125644
  /**
125602
125645
  * Resolve a (possibly qualified) name to its symbol per §7.5.1, searching
125603
125646
  * outward from namespace `start` and its enclosing namespaces (its own resolved
@@ -125609,28 +125652,48 @@ var NamespaceResolver = class {
125609
125652
  * its own enclosing package already imported, per §7.5.1/§7.5.3).
125610
125653
  */
125611
125654
  resolveQualifiedNameFrom(start, name, indexes) {
125655
+ return this.resolveQualifiedReferenceFrom(start, name, indexes).symbol;
125656
+ }
125657
+ resolveQualifiedReferenceFrom(start, name, indexes) {
125612
125658
  const [first, ...rest] = splitQualifiedName(name);
125613
125659
  let resolved;
125614
125660
  for (const ancestor of this.namespaceAncestorsOf(start, indexes)) {
125615
125661
  const candidates = this.getResolvedMembers(ancestor, indexes).get(first);
125616
125662
  if (candidates && candidates.length > 0) {
125663
+ if (this.isAmbiguous(first, candidates, indexes)) return { ambiguous: true };
125617
125664
  resolved = candidates[0].symbol;
125618
125665
  break;
125619
125666
  }
125620
125667
  }
125621
- if (resolved === void 0) return void 0;
125668
+ if (resolved === void 0) return { ambiguous: false };
125622
125669
  const isWithinStart = (namespace) => this.namespaceAncestorsOf(start, indexes).has(namespace);
125623
125670
  for (const segment of rest) {
125624
125671
  const owner = resolved;
125625
125672
  const ownerKey = namespaceKeyOf(owner);
125626
125673
  const members = this.getResolvedMembers(ownerKey, indexes).get(segment);
125674
+ if (members && this.isAmbiguous(segment, members, indexes)) return { ambiguous: true };
125627
125675
  const visibleMember = members?.find(
125628
125676
  (m2) => m2.visibility === "public" || isWithinStart(ownerKey) || m2.visibility === "protected" && this.isProtectedVisibleFrom(start, owner, indexes)
125629
125677
  );
125630
- if (!visibleMember) return void 0;
125678
+ if (!visibleMember) return { ambiguous: false };
125631
125679
  resolved = visibleMember.symbol;
125632
125680
  }
125633
- return resolved.qualifiedName !== void 0 ? indexes.byQualifiedName.get(resolved.qualifiedName) : resolved;
125681
+ return this.referenceTo(resolved, indexes);
125682
+ }
125683
+ referenceTo(resolved, indexes) {
125684
+ if (!resolved) return { ambiguous: false };
125685
+ const symbol = resolved.qualifiedName !== void 0 ? indexes.byQualifiedName.get(resolved.qualifiedName) : resolved;
125686
+ return { symbol, ambiguous: symbol === void 0 };
125687
+ }
125688
+ /**
125689
+ * Whether `name` names more than one of `candidates` that clash on it
125690
+ * through a short name (`SymbolIndexes.clashingShortNames`), so it can't
125691
+ * be resolved to either (KerML 7.2.5.2). Like a conflicted qualifiedName,
125692
+ * it doesn't fall through to an enclosing namespace's member of that name.
125693
+ */
125694
+ isAmbiguous(name, candidates, indexes) {
125695
+ const clashing = indexes.clashingShortNames.get(name);
125696
+ return clashing !== void 0 && candidates.filter((c) => clashing.has(c.symbol)).length > 1;
125634
125697
  }
125635
125698
  /**
125636
125699
  * §7.5.3's protected-import exception: "A visibility of protected is the
@@ -128333,9 +128396,11 @@ var NameReferences = class {
128333
128396
  if (target && !path3.qualifiedNames.some((name) => name.segments.some((segment) => segment.name === target.name || segment.name === target.shortName))) continue;
128334
128397
  const namespace = namespaces.find((ns) => ns.body < path3.start && path3.end <= ns.end);
128335
128398
  let receiver;
128399
+ let receiverAmbiguous = false;
128336
128400
  for (let group = 0; group < path3.qualifiedNames.length; group++) {
128337
128401
  const qualified = path3.qualifiedNames[group];
128338
128402
  let resolved;
128403
+ let ambiguous = false;
128339
128404
  for (let index2 = 0; index2 < qualified.segments.length; index2++) {
128340
128405
  const segment = qualified.segments[index2];
128341
128406
  const range = import_node4.Range.create(doc.positionAt(segment.start), doc.positionAt(segment.end));
@@ -128344,17 +128409,27 @@ var NameReferences = class {
128344
128409
  while (before >= 0 && /\s/.test(text[before])) before--;
128345
128410
  while (after < text.length && /\s/.test(text[after])) after++;
128346
128411
  const declaration = symbols.find((symbol) => !isAnonymous(symbol) && (symbol.selectionRange.start.line === range.start.line && symbol.selectionRange.start.character === range.start.character && symbol.selectionRange.end.character === range.end.character || symbol.shortName === segment.name && text[before] === "<" && text[after] === ">" && doc.offsetAt(symbol.range.start) <= segment.start && segment.end < doc.offsetAt(symbol.selectionRange.start)));
128347
- if (declaration) resolved = declaration;
128348
- else if (index2 > 0) {
128349
- resolved = resolved ? this.resolver.getResolvedMembers(namespaceKeyOf(resolved), this.indexes).get(segment.name)?.find((entry) => entry.visibility === "public")?.symbol : void 0;
128412
+ if (declaration) {
128413
+ resolved = declaration;
128414
+ ambiguous = false;
128415
+ } else if (index2 > 0) {
128416
+ if (resolved) {
128417
+ const result = this.resolver.resolveMemberReference(resolved, segment.name, this.indexes);
128418
+ resolved = result.symbol;
128419
+ ambiguous = result.ambiguous;
128420
+ }
128350
128421
  } else if (group > 0) {
128351
- resolved = receiver ? this.resolveFeature(receiver, segment.name) : void 0;
128422
+ const result = receiver ? this.resolveFeature(receiver, segment.name) : { ambiguous: receiverAmbiguous };
128423
+ resolved = result.symbol;
128424
+ ambiguous = result.ambiguous;
128352
128425
  } else {
128353
- resolved = this.resolver.resolveNameIn(
128426
+ const result = this.resolver.resolveReferenceIn(
128354
128427
  namespace?.symbol,
128355
128428
  joinQualifiedName([segment.name]),
128356
128429
  this.indexes
128357
128430
  );
128431
+ resolved = result.symbol;
128432
+ ambiguous = result.ambiguous;
128358
128433
  }
128359
128434
  if (cursor !== void 0 && (cursor < segment.start || cursor > segment.end)) continue;
128360
128435
  if (target && segment.name !== target.name && segment.name !== target.shortName) continue;
@@ -128364,10 +128439,12 @@ var NameReferences = class {
128364
128439
  name: segment.name,
128365
128440
  qualifiedName: index2 === qualified.segments.length - 1 ? qualified.name : segment.name,
128366
128441
  symbol: resolved,
128367
- isDeclaration: declaration !== void 0
128442
+ isDeclaration: declaration !== void 0,
128443
+ isAmbiguous: ambiguous
128368
128444
  });
128369
128445
  }
128370
128446
  receiver = resolved;
128447
+ receiverAmbiguous = ambiguous;
128371
128448
  }
128372
128449
  }
128373
128450
  return refs;
@@ -128379,14 +128456,14 @@ var NameReferences = class {
128379
128456
  const owner = queue[index2];
128380
128457
  if (visited.has(owner)) continue;
128381
128458
  visited.add(owner);
128382
- const member = this.resolver.getResolvedMembers(namespaceKeyOf(owner), this.indexes).get(name)?.find((entry) => entry.visibility === "public")?.symbol;
128383
- if (member) return member;
128459
+ const member = this.resolver.resolveMemberReference(owner, name, this.indexes);
128460
+ if (member.symbol || member.ambiguous) return member;
128384
128461
  for (const typeName of owner.typeNames) {
128385
128462
  const type = this.resolver.resolveNameFrom(owner, typeName, this.indexes);
128386
128463
  if (type && !visited.has(type)) queue.push(type);
128387
128464
  }
128388
128465
  }
128389
- return void 0;
128466
+ return { ambiguous: false };
128390
128467
  }
128391
128468
  };
128392
128469
 
@@ -128403,6 +128480,7 @@ var DefinitionProvider = class {
128403
128480
  }
128404
128481
  const wsSymbolTable = this.documentManager.getWorkspaceSymbolTable();
128405
128482
  const reference = new NameReferences(this.documentManager).at(params.textDocument.uri, params.position);
128483
+ if (reference?.isAmbiguous) return null;
128406
128484
  if (reference?.symbol && !reference.isDeclaration) {
128407
128485
  return { uri: reference.symbol.uri, range: reference.symbol.selectionRange };
128408
128486
  }
@@ -129017,6 +129095,7 @@ var HoverProvider = class {
129017
129095
  }
129018
129096
  const text = this.documentManager.getText(params.textDocument.uri);
129019
129097
  const reference = new NameReferences(this.documentManager).at(params.textDocument.uri, params.position);
129098
+ if (reference?.isAmbiguous) return null;
129020
129099
  const word = reference?.qualifiedName ?? (text ? this.getWordAtPosition(text, params.position.line, params.position.character) : void 0);
129021
129100
  if (word && word.includes("::") && !reference?.symbol) {
129022
129101
  const libHover = this.buildLibraryHover(word);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "sysml-v2-lsp",
3
3
  "displayName": "SysML v2 Language Server",
4
4
  "description": "Language Server Protocol implementation for SysML v2, powered by ANTLR4",
5
- "version": "0.38.0",
5
+ "version": "0.39.0",
6
6
  "publisher": "JamieD",
7
7
  "license": "MIT",
8
8
  "repository": {