plaxtony
Version:
Static code analysis of SC2 Galaxy Script
478 lines • 19.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDiagnosticForNode = exports.createFileDiagnostic = exports.forEachChild = exports.fixupParentReferences = exports.getSourceFileOfNode = exports.findAncestorByKind = exports.findAncestor = exports.sourceFileToJSON = exports.getKindName = exports.isRightSideOfPropertyAccess = exports.isPartOfTypeNode = exports.isPartOfExpression = exports.isLeftHandSideExpression = exports.isDeclarationKind = exports.isNamedDeclarationKind = exports.isContainerKind = exports.isLeftHandSideExpressionKind = exports.isAssignmentExpression = exports.isAssignmentOperator = exports.isComparisonOperator = exports.isReferenceKeywordKind = exports.isComplexTypeKind = exports.isKeywordTypeKind = exports.isKeywordKind = exports.isModifierKind = exports.isToken = void 0;
const gt = require("./types");
/**
* True if node is of some token syntax kind.
* For example, this is true for an IfKeyword but not for an IfStatement.
*/
function isToken(n) {
return n.kind >= 2 /* FirstToken */ && n.kind <= 113 /* LastToken */;
}
exports.isToken = isToken;
function isModifierKind(token) {
switch (token) {
case 53 /* ConstKeyword */:
case 52 /* StaticKeyword */:
case 54 /* NativeKeyword */:
return true;
}
return false;
}
exports.isModifierKind = isModifierKind;
function isKeywordKind(token) {
return token >= 50 /* FirstKeyword */ && token <= 112 /* LastKeyword */;
}
exports.isKeywordKind = isKeywordKind;
function isKeywordTypeKind(token) {
return token >= 71 /* FirstKeywordType */ && token <= 117 /* LastKeywordType */;
}
exports.isKeywordTypeKind = isKeywordTypeKind;
function isComplexTypeKind(token) {
if (77 /* FirstComplexType */ <= token && 109 /* LastComplexType */ >= token) {
return true;
}
return false;
}
exports.isComplexTypeKind = isComplexTypeKind;
function isReferenceKeywordKind(token) {
switch (token) {
case 110 /* ArrayrefKeyword */:
case 111 /* StructrefKeyword */:
case 112 /* FuncrefKeyword */:
return true;
}
return false;
}
exports.isReferenceKeywordKind = isReferenceKeywordKind;
function isComparisonOperator(token) {
return token >= 13 /* LessThanToken */ && token <= 19 /* EqualsGreaterThanToken */;
}
exports.isComparisonOperator = isComparisonOperator;
function isAssignmentOperator(token) {
return token >= 39 /* EqualsToken */ && token <= 49 /* CaretEqualsToken */;
}
exports.isAssignmentOperator = isAssignmentOperator;
function isAssignmentExpression(node) {
switch (node.kind) {
case 124 /* BinaryExpression */:
return isAssignmentOperator(node.operatorToken.kind);
case 126 /* ParenthesizedExpression */:
return isAssignmentExpression(node.expression);
default:
return false;
}
}
exports.isAssignmentExpression = isAssignmentExpression;
function isLeftHandSideExpressionKind(kind) {
return kind === 120 /* PropertyAccessExpression */
|| kind === 119 /* ElementAccessExpression */
|| kind === 121 /* CallExpression */
|| kind === 126 /* ParenthesizedExpression */
|| kind === 118 /* ArrayLiteralExpression */
|| kind === 113 /* Identifier */
|| kind === 2 /* NumericLiteral */
|| kind === 3 /* StringLiteral */
|| kind === 68 /* FalseKeyword */
|| kind === 69 /* NullKeyword */
|| kind === 67 /* TrueKeyword */;
}
exports.isLeftHandSideExpressionKind = isLeftHandSideExpressionKind;
function isContainerKind(kind) {
return kind === 127 /* SourceFile */
|| kind === 142 /* FunctionDeclaration */
|| kind === 140 /* StructDeclaration */;
}
exports.isContainerKind = isContainerKind;
function isNamedDeclarationKind(kind) {
return kind === 127 /* SourceFile */
|| kind === 141 /* VariableDeclaration */
|| kind === 142 /* FunctionDeclaration */
|| kind === 140 /* StructDeclaration */
|| kind === 144 /* PropertyDeclaration */
|| kind === 143 /* ParameterDeclaration */
|| kind === 145 /* TypedefDeclaration */;
}
exports.isNamedDeclarationKind = isNamedDeclarationKind;
function isDeclarationKind(kind) {
return isNamedDeclarationKind(kind);
}
exports.isDeclarationKind = isDeclarationKind;
function isLeftHandSideExpression(node) {
return isLeftHandSideExpressionKind(node.kind);
}
exports.isLeftHandSideExpression = isLeftHandSideExpression;
function isPartOfExpression(node) {
switch (node.kind) {
case 69 /* NullKeyword */:
case 67 /* TrueKeyword */:
case 68 /* FalseKeyword */:
case 118 /* ArrayLiteralExpression */:
case 120 /* PropertyAccessExpression */:
case 119 /* ElementAccessExpression */:
case 121 /* CallExpression */:
case 125 /* TypeAssertionExpression */:
case 126 /* ParenthesizedExpression */:
case 122 /* PrefixUnaryExpression */:
case 123 /* PostfixUnaryExpression */:
case 124 /* BinaryExpression */:
case 113 /* Identifier */:
return true;
case 2 /* NumericLiteral */:
case 3 /* StringLiteral */:
const parent = node.parent;
switch (parent.kind) {
case 141 /* VariableDeclaration */:
case 144 /* PropertyDeclaration */:
case 138 /* ExpressionStatement */:
case 129 /* IfStatement */:
case 130 /* DoStatement */:
case 131 /* WhileStatement */:
case 137 /* ReturnStatement */:
case 132 /* ForStatement */:
const forStatement = parent;
return (forStatement.initializer === node) ||
forStatement.condition === node ||
forStatement.incrementor === node;
default:
if (isPartOfExpression(parent)) {
return true;
}
}
}
return false;
}
exports.isPartOfExpression = isPartOfExpression;
function isPartOfTypeNode(node) {
if (115 /* FirstTypeNode */ <= node.kind && node.kind <= 117 /* LastTypeNode */) {
return true;
}
switch (node.kind) {
case 74 /* IntKeyword */:
case 75 /* FixedKeyword */:
case 76 /* StringKeyword */:
case 71 /* BoolKeyword */:
case 106 /* VoidKeyword */:
return true;
// Identifiers and qualified names may be type nodes, depending on their context. Climb
// above them to find the lowest container
case 113 /* Identifier */:
// If the identifier is the RHS of a qualified name, then it's a type iff its parent is.
if (node.parent.kind === 120 /* PropertyAccessExpression */ && node.parent.name === node) {
node = node.parent;
}
// At this point, node is either a qualified name or an identifier
// Debug.assert(node.kind === gt.SyntaxKind.Identifier || node.kind === gt.SyntaxKind.QualifiedName || node.kind === gt.SyntaxKind.PropertyAccessExpression,
// "'node' was expected to be a qualified name, identifier or property access in 'isPartOfTypeNode'.");
// falls through
case 120 /* PropertyAccessExpression */:
const parent = node.parent;
// Do not recursively call isPartOfTypeNode on the parent. In the example:
//
// let a: A.B.C;
//
// Calling isPartOfTypeNode would consider the qualified name A.B a type node.
// Only C and A.B.C are type nodes.
if (115 /* FirstTypeNode */ <= parent.kind && parent.kind <= 117 /* LastTypeNode */) {
return true;
}
switch (parent.kind) {
case 144 /* PropertyDeclaration */:
case 143 /* ParameterDeclaration */:
case 141 /* VariableDeclaration */:
return node === parent.type;
case 142 /* FunctionDeclaration */:
return node === parent.type;
// TODO:
// case gt.SyntaxKind.CallExpression:
// return (<gt.CallExpression>parent).typeArguments && indexOf((<gt.CallExpression>parent).typeArguments, node) >= 0;
}
}
return false;
}
exports.isPartOfTypeNode = isPartOfTypeNode;
function isRightSideOfPropertyAccess(node) {
return (node.parent.kind === 120 /* PropertyAccessExpression */ && node.parent.name === node);
}
exports.isRightSideOfPropertyAccess = isRightSideOfPropertyAccess;
function isNodeOrArray(a) {
return a !== undefined && a.kind !== undefined;
}
function getKindName(k) {
if (typeof k === "string") {
return k;
}
return gt.SyntaxKind[k];
}
exports.getKindName = getKindName;
function sourceFileToJSON(file) {
return JSON.stringify(file, (_, v) => isNodeOrArray(v) ? serializeNode(v) : v, " ");
function serializeNode(n) {
const o = { kind: getKindName(n.kind) };
// if (ts.containsParseError(n)) {
// o.containsParseError = true;
// }
for (let propertyName in n) {
switch (propertyName) {
case "parent":
case "symbol":
case "locals":
case "localSymbol":
case "kind":
case "semanticDiagnostics":
case "id":
case "nodeCount":
case "symbolCount":
case "identifierCount":
case "scriptSnapshot":
// Blacklist of items we never put in the baseline file.
break;
case "originalKeywordKind":
o[propertyName] = getKindName(n[propertyName]);
break;
case "flags":
// Clear the flags that are produced by aggregating child values. That is ephemeral
// data we don't care about in the dump. We only care what the parser set directly
// on the AST.
// const flags = n.flags & ~(ts.NodeFlags.JavaScriptFile | ts.NodeFlags.HasAggregatedChildData);
// if (flags) {
// o[propertyName] = getNodeFlagName(flags);
// }
break;
case "referenceDiagnostics":
case "parseDiagnostics":
// o[propertyName] = Utils.convertDiagnostics((<any>n)[propertyName]);
break;
// case "nextContainer":
// if (n.nextContainer) {
// o[propertyName] = { kind: n.nextContainer.kind, pos: n.nextContainer.pos, end: n.nextContainer.end };
// }
// break;
case "text":
// Include 'text' field for identifiers/literals, but not for source files.
if (n.kind !== 127 /* SourceFile */) {
o[propertyName] = n[propertyName];
}
break;
default:
o[propertyName] = n[propertyName];
}
}
return o;
}
}
exports.sourceFileToJSON = sourceFileToJSON;
function findAncestor(node, callback) {
while (node) {
const result = callback(node);
if (result === "quit") {
return undefined;
}
else if (result) {
return node;
}
node = node.parent;
}
return undefined;
}
exports.findAncestor = findAncestor;
function findAncestorByKind(node, kind) {
while (node && node.kind !== kind) {
node = node.parent;
}
return node;
}
exports.findAncestorByKind = findAncestorByKind;
function getSourceFileOfNode(node) {
while (node && node.kind !== 127 /* SourceFile */) {
node = node.parent;
}
return node;
}
exports.getSourceFileOfNode = getSourceFileOfNode;
function fixupParentReferences(rootNode) {
let parent = rootNode;
forEachChild(rootNode, visitNode);
function visitNode(n) {
// walk down setting parents that differ from the parent we think it should be. This
// allows us to quickly bail out of setting parents for subtrees during incremental
// parsing
if (n.parent !== parent) {
n.parent = parent;
const saveParent = parent;
parent = n;
forEachChild(n, visitNode);
parent = saveParent;
}
}
}
exports.fixupParentReferences = fixupParentReferences;
function visitNode(cbNode, node) {
return node && cbNode(node);
}
function visitNodes(cbNode, cbNodes, nodes) {
if (nodes) {
if (cbNodes) {
return cbNodes(nodes);
}
for (const node of nodes) {
const result = cbNode(node);
if (result) {
return result;
}
}
}
}
/**
* Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes
* stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise,
* embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns
* a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned.
*
* @param node a given node to visit its children
* @param cbNode a callback to be invoked for all child nodes
* @param cbNodes a callback to be invoked for embedded array
*
* @remarks `forEachChild` must visit the children of a node in the order
* that they appear in the source code.
*/
function forEachChild(node, cbNode, cbNodes) {
if (!node || !node.kind) {
return;
}
switch (node.kind) {
case 144 /* PropertyDeclaration */:
return visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, node.type) ||
visitNode(cbNode, node.name);
case 141 /* VariableDeclaration */:
return visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, node.type) ||
visitNode(cbNode, node.name) ||
visitNode(cbNode, node.initializer);
case 142 /* FunctionDeclaration */:
return visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, node.type) ||
visitNode(cbNode, node.name) ||
visitNodes(cbNode, cbNodes, node.parameters) ||
visitNode(cbNode, node.body);
case 140 /* StructDeclaration */:
return visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, node.name) ||
visitNodes(cbNode, cbNodes, node.members);
case 143 /* ParameterDeclaration */:
return visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, node.name) ||
visitNode(cbNode, node.type);
case 145 /* TypedefDeclaration */:
return visitNode(cbNode, node.type) ||
visitNode(cbNode, node.name);
case 117 /* ArrayType */:
return visitNode(cbNode, node.elementType) ||
visitNode(cbNode, node.size);
case 116 /* MappedType */:
return visitNode(cbNode, node.returnType) ||
visitNodes(cbNode, cbNodes, node.typeArguments);
case 120 /* PropertyAccessExpression */:
return visitNode(cbNode, node.expression) ||
visitNode(cbNode, node.name);
case 119 /* ElementAccessExpression */:
return visitNode(cbNode, node.expression) ||
visitNode(cbNode, node.argumentExpression);
case 121 /* CallExpression */:
return visitNode(cbNode, node.expression) ||
visitNodes(cbNode, cbNodes, node.arguments);
case 126 /* ParenthesizedExpression */:
return visitNode(cbNode, node.expression);
case 122 /* PrefixUnaryExpression */:
return visitNode(cbNode, node.operator) ||
visitNode(cbNode, node.operand);
case 123 /* PostfixUnaryExpression */:
return visitNode(cbNode, node.operand) ||
visitNode(cbNode, node.operator);
case 124 /* BinaryExpression */:
return visitNode(cbNode, node.left) ||
visitNode(cbNode, node.operatorToken) ||
visitNode(cbNode, node.right);
case 128 /* Block */:
return visitNodes(cbNode, cbNodes, node.statements);
case 127 /* SourceFile */:
return visitNodes(cbNode, cbNodes, node.statements);
case 138 /* ExpressionStatement */:
return visitNode(cbNode, node.expression);
case 129 /* IfStatement */:
return visitNode(cbNode, node.expression) ||
visitNode(cbNode, node.thenStatement) ||
visitNode(cbNode, node.elseStatement);
case 130 /* DoStatement */:
return visitNode(cbNode, node.statement) ||
visitNode(cbNode, node.expression);
case 131 /* WhileStatement */:
return visitNode(cbNode, node.expression) ||
visitNode(cbNode, node.statement);
case 132 /* ForStatement */:
return visitNode(cbNode, node.initializer) ||
visitNode(cbNode, node.condition) ||
visitNode(cbNode, node.incrementor) ||
visitNode(cbNode, node.statement);
case 134 /* ContinueStatement */:
case 133 /* BreakStatement */:
case 135 /* BreakpointStatement */:
break;
case 137 /* ReturnStatement */:
return visitNode(cbNode, node.expression);
case 136 /* IncludeStatement */:
return visitNode(cbNode, node.path);
}
}
exports.forEachChild = forEachChild;
class Diagnostic {
constructor(file, code, messageText, start, length) {
this.file = file;
this.code = code;
this.messageText = messageText;
this.start = start;
this.length = length;
}
toString() {
var _a;
return `${(_a = this.file) === null || _a === void 0 ? void 0 : _a.fileName} [${this.start}]: ${this.messageText}`.toString();
}
}
function createFileDiagnostic(file, start, length, message) {
// const end = start + length;
return {
file: file,
code: message.code,
category: message.category,
start: start,
length: length,
messageText: message.message,
toString() {
var _a;
return `${(_a = this.file) === null || _a === void 0 ? void 0 : _a.fileName} [${this.start}]: ${this.messageText}`.toString();
}
};
}
exports.createFileDiagnostic = createFileDiagnostic;
function createDiagnosticForNode(node, category, msg, tags) {
const d = {
file: getSourceFileOfNode(node),
category: category,
start: node.pos,
length: node.end - node.pos,
line: node.line,
col: node.char,
messageText: msg,
toString() {
var _a;
return `${(_a = this.file) === null || _a === void 0 ? void 0 : _a.fileName} [${this.start}]: ${this.messageText}`.toString();
}
};
if (tags) {
d.tags = tags.concat();
}
return d;
}
exports.createDiagnosticForNode = createDiagnosticForNode;
//# sourceMappingURL=utils.js.map