UNPKG

@neo-one/smart-contract-compiler

Version:

NEO•ONE TypeScript smart contract compiler.

165 lines (163 loc) 6.78 kB
import { tsUtils } from '@neo-one/ts-utils'; import { utils } from '@neo-one/utils'; import _ from 'lodash'; import ts from 'typescript'; import { toABIReturn } from '../utils'; export class DebugInfoProcessor { constructor(context, contractInfo) { this.context = context; this.contractInfo = contractInfo; this.sourceFile = contractInfo.smartContract.getSourceFile(); this.endLine = this.sourceFile.getLineAndCharacterOfPosition(this.sourceFile.getEnd()).line; } process() { return { entrypoint: '', documents: [this.sourceFile.fileName], methods: this.processMethods(), events: [], }; } processMethods() { const propInfos = this.contractInfo.propInfos.filter(utils.notNull); return _.flatten(propInfos.map((propInfo) => { switch (propInfo.type) { case 'function': const funcRange = this.getSourceRange(propInfo.decl); if (funcRange === undefined) { return []; } return [ { id: '', name: propInfo.name, params: this.getParameters({ callSignature: propInfo.callSignature, send: propInfo.send, claim: propInfo.claim, }), range: funcRange, returnType: this.toDebugReturn(propInfo.decl, propInfo.returnType), }, ]; case 'property': const propRange = this.getSourceRange(propInfo.decl); if (propRange === undefined) { return []; } return [ { id: '', name: propInfo.name, params: [], range: propRange, returnType: this.toDebugReturn(propInfo.decl, propInfo.propertyType), }, ]; case 'accessor': return [this.getGetterInfo(propInfo), this.getSetterInfo(propInfo)].filter(utils.notNull); default: return []; } })); } getGetterInfo(propInfo) { if (propInfo.getter === undefined) { return undefined; } const range = this.getSourceRange(propInfo.getter.decl); if (range === undefined) { return undefined; } return { id: '', name: propInfo.getter.name, params: [], range, returnType: this.toDebugReturn(propInfo.getter.decl, propInfo.propertyType), }; } getSetterInfo(propInfo) { if (propInfo.setter === undefined) { return undefined; } const range = this.getSourceRange(propInfo.setter.decl); if (range === undefined) { return undefined; } return { id: '', name: propInfo.setter.name, params: [ this.toDebugParameter(propInfo.name, propInfo.getter === undefined ? propInfo.setter.decl : propInfo.getter.decl, propInfo.propertyType, false, propInfo.getter === undefined ? { error: true } : undefined), ].filter(utils.notNull), range, returnType: 'Void', }; } getParameters({ callSignature, claim = false, send = false, }) { if (callSignature === undefined) { return []; } let parameters = callSignature.getParameters(); if (claim && this.checkLastParam(parameters, 'ClaimTransaction')) { parameters = parameters.slice(0, -1); } if (send && this.checkLastParam(parameters, 'Transfer')) { parameters = parameters.slice(0, -1); } return parameters.map((parameter) => this.paramToABIParameter(parameter)).filter(utils.notNull); } paramToABIParameter(param) { const decls = tsUtils.symbol.getDeclarations(param); const decl = utils.nullthrows(decls[0]); const initializer = tsUtils.initializer.getInitializer(decl); return this.toDebugParameter(tsUtils.symbol.getName(param), decl, this.getParamSymbolType(param), initializer !== undefined); } getParamSymbolType(param) { const decls = tsUtils.symbol.getDeclarations(param); const decl = utils.nullthrows(decls[0]); return this.context.analysis.getTypeOfSymbol(param, decl); } checkLastParam(parameters, value) { return this.checkLastParamBase(parameters, (decl, type) => this.context.builtins.isInterface(decl, type, value)); } checkLastParamBase(parameters, checkParamType) { if (parameters.length === 0) { return false; } const lastParam = parameters[parameters.length - 1]; const lastParamType = this.getParamSymbolType(lastParam); return lastParamType !== undefined && checkParamType(tsUtils.symbol.getDeclarations(lastParam)[0], lastParamType); } toDebugParameter(nameIn, node, resolvedTypeIn, optional = false, options = { error: false, warning: false }) { const name = nameIn.startsWith('_') ? nameIn.slice(1) : nameIn; let resolvedType = resolvedTypeIn; if (ts.isParameter(node) && tsUtils.parameter.isRestParameter(node) && resolvedType !== undefined) { resolvedType = tsUtils.type_.getTypeArgumentsArray(resolvedType)[0]; } const type = toABIReturn(this.context, node, resolvedType, optional, options); if (type === undefined) { return undefined; } return `${name},${type.type}`; } toDebugReturn(node, resolvedType, optional = false, options = { error: false, warning: false }) { const type = toABIReturn(this.context, node, resolvedType, optional, options); return type === undefined ? 'Void' : type.type; } getSourceRange(node) { try { const { line: start } = this.sourceFile.getLineAndCharacterOfPosition(node.getStart()); const { line: end } = this.sourceFile.getLineAndCharacterOfPosition(node.getEnd()); if (start === this.endLine && end === this.endLine) { return undefined; } return [start, end]; } catch { return undefined; } } } //# sourceMappingURL=DebugInfoProcessor.js.map