Files
infocom-systems-design/node_modules/langium/lib/grammar/references/grammar-references.js
2025-10-03 22:27:28 +03:00

157 lines
7.3 KiB
JavaScript

/******************************************************************************
* Copyright 2021 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import { DefaultReferences } from '../../references/references.js';
import { getContainerOfType, getDocument } from '../../utils/ast-utils.js';
import { toDocumentSegment } from '../../utils/cst-utils.js';
import { findAssignment, findNodeForProperty, getActionAtElement } from '../../utils/grammar-utils.js';
import { stream } from '../../utils/stream.js';
import { UriUtils } from '../../utils/uri-utils.js';
import { isAction, isAssignment, isInterface, isParserRule, isType, isTypeAttribute } from '../../languages/generated/ast.js';
import { extractAssignments } from '../internal-grammar-util.js';
import { collectChildrenTypes, collectSuperTypes } from '../type-system/types-util.js';
export class LangiumGrammarReferences extends DefaultReferences {
constructor(services) {
super(services);
this.documents = services.shared.workspace.LangiumDocuments;
}
findDeclaration(sourceCstNode) {
const nodeElem = sourceCstNode.astNode;
const assignment = findAssignment(sourceCstNode);
if (assignment && assignment.feature === 'feature') {
// Only search for a special declaration if the cst node is the feature property of the action/assignment
if (isAssignment(nodeElem)) {
return this.findAssignmentDeclaration(nodeElem);
}
else if (isAction(nodeElem)) {
return this.findActionDeclaration(nodeElem);
}
}
return super.findDeclaration(sourceCstNode);
}
findReferences(targetNode, options) {
var _a;
if (isTypeAttribute(targetNode)) {
return this.findReferencesToTypeAttribute(targetNode, (_a = options.includeDeclaration) !== null && _a !== void 0 ? _a : false);
}
else {
return super.findReferences(targetNode, options);
}
}
findReferencesToTypeAttribute(targetNode, includeDeclaration) {
const refs = [];
const interfaceNode = getContainerOfType(targetNode, isInterface);
if (interfaceNode) {
if (includeDeclaration) {
const ref = this.getReferenceToSelf(targetNode);
if (ref) {
refs.push(ref);
}
}
const interfaces = collectChildrenTypes(interfaceNode, this, this.documents, this.nodeLocator);
const targetRules = [];
interfaces.forEach(interf => {
const rules = this.findRulesWithReturnType(interf);
targetRules.push(...rules);
});
targetRules.forEach(rule => {
const references = this.createReferencesToAttribute(rule, targetNode);
refs.push(...references);
});
}
return stream(refs);
}
createReferencesToAttribute(ruleOrAction, attribute) {
const refs = [];
if (isParserRule(ruleOrAction)) {
const assignment = extractAssignments(ruleOrAction.definition).find(a => a.feature === attribute.name);
if (assignment === null || assignment === void 0 ? void 0 : assignment.$cstNode) {
const leaf = this.nameProvider.getNameNode(assignment);
if (leaf) {
refs.push({
sourceUri: getDocument(assignment).uri,
sourcePath: this.nodeLocator.getAstNodePath(assignment),
targetUri: getDocument(attribute).uri,
targetPath: this.nodeLocator.getAstNodePath(attribute),
segment: toDocumentSegment(leaf),
local: UriUtils.equals(getDocument(assignment).uri, getDocument(attribute).uri)
});
}
}
}
else {
// If the action references the attribute directly
if (ruleOrAction.feature === attribute.name) {
const leaf = findNodeForProperty(ruleOrAction.$cstNode, 'feature');
if (leaf) {
refs.push({
sourceUri: getDocument(ruleOrAction).uri,
sourcePath: this.nodeLocator.getAstNodePath(ruleOrAction),
targetUri: getDocument(attribute).uri,
targetPath: this.nodeLocator.getAstNodePath(attribute),
segment: toDocumentSegment(leaf),
local: UriUtils.equals(getDocument(ruleOrAction).uri, getDocument(attribute).uri)
});
}
}
// Find all references within the parser rule that contains this action
const parserRule = getContainerOfType(ruleOrAction, isParserRule);
refs.push(...this.createReferencesToAttribute(parserRule, attribute));
}
return refs;
}
findAssignmentDeclaration(assignment) {
var _a;
const parserRule = getContainerOfType(assignment, isParserRule);
const action = getActionAtElement(assignment);
if (action) {
const actionDeclaration = this.findActionDeclaration(action, assignment.feature);
if (actionDeclaration) {
return actionDeclaration;
}
}
if ((_a = parserRule === null || parserRule === void 0 ? void 0 : parserRule.returnType) === null || _a === void 0 ? void 0 : _a.ref) {
if (isInterface(parserRule.returnType.ref) || isType(parserRule.returnType.ref)) {
const interfaces = collectSuperTypes(parserRule.returnType.ref);
for (const interf of interfaces) {
const typeAttribute = interf.attributes.find(att => att.name === assignment.feature);
if (typeAttribute) {
return typeAttribute;
}
}
}
}
return assignment;
}
findActionDeclaration(action, featureName) {
var _a;
if ((_a = action.type) === null || _a === void 0 ? void 0 : _a.ref) {
const feature = featureName !== null && featureName !== void 0 ? featureName : action.feature;
const interfaces = collectSuperTypes(action.type.ref);
for (const interf of interfaces) {
const typeAttribute = interf.attributes.find(att => att.name === feature);
if (typeAttribute) {
return typeAttribute;
}
}
}
return undefined;
}
findRulesWithReturnType(interf) {
const rules = [];
const refs = this.index.findAllReferences(interf, this.nodeLocator.getAstNodePath(interf));
for (const ref of refs) {
const doc = this.documents.getDocument(ref.sourceUri);
if (doc) {
const astNode = this.nodeLocator.getAstNode(doc.parseResult.value, ref.sourcePath);
if (isParserRule(astNode) || isAction(astNode)) {
rules.push(astNode);
}
}
}
return rules;
}
}
//# sourceMappingURL=grammar-references.js.map