@solvprotocol/upgrade-safe-transpiler
Version:
Solidity preprocessor used to generate OpenZeppelin Contracts Upgrade Safe.
89 lines (78 loc) • 2.67 kB
text/typescript
import { SourceUnit } from 'solidity-ast';
import { Node } from 'solidity-ast/node';
import { findAll } from 'solidity-ast/utils';
import { getNodeBounds } from '../solc/ast-utils';
import { Transformation } from './type';
import { renameContract } from '../rename';
import { ASTResolver } from '../ast-resolver';
import { TransformerTools } from '../transform';
function* findAllIdentifiers(node: Node) {
const seen = new Set();
for (const id of findAll(['UserDefinedTypeName', 'IdentifierPath', 'Identifier'], node)) {
if ('pathNode' in id && id.pathNode !== undefined) {
seen.add(id.pathNode);
}
if (!seen.has(id)) {
yield id;
}
}
}
export function* renameIdentifiers(
sourceUnit: SourceUnit,
{ resolver }: TransformerTools,
): Generator<Transformation> {
const candidates = getTransitiveRenameCandidates(sourceUnit, resolver);
const rename = new Set(
Object.keys(candidates).filter(name => resolver.resolveContract(candidates[name])),
);
for (const ident of findAllIdentifiers(sourceUnit)) {
const ref = ident.referencedDeclaration;
const contract = ref != null ? resolver.resolveContract(ref) : undefined;
const identName = 'pathNode' in ident ? ident.pathNode?.name : ident.name;
if (identName === undefined) {
throw new Error('Unrecognized AST');
}
if (contract && rename.has(contract.name)) {
yield {
kind: 'rename-identifiers',
text: renameContract(identName),
...getNodeBounds(ident),
};
} else if (identName.includes('.')) {
const [ns] = identName.split('.', 1);
if (rename.has(ns)) {
yield {
kind: 'rename-identifiers',
transform: s => s.replace(ns, renameContract(ns)),
...getNodeBounds(ident),
};
}
}
}
}
function getTransitiveRenameCandidates(
sourceUnit: SourceUnit,
resolver: ASTResolver,
): Record<string, number> {
const ex: Record<string, number> = {};
for (const sym in sourceUnit.exportedSymbols) {
const ids = sourceUnit.exportedSymbols[sym];
if (ids) {
ex[sym] = ids[0];
}
}
for (const imp of findAll('ImportDirective', sourceUnit)) {
const referencedSourceUnit = resolver.resolveNode('SourceUnit', imp.sourceUnit);
const subexports = getTransitiveRenameCandidates(referencedSourceUnit, resolver);
if (imp.symbolAliases.length === 0) {
Object.assign(ex, subexports);
} else {
for (const { foreign, local } of imp.symbolAliases) {
if (local == null || foreign.name === local) {
ex[foreign.name] = subexports[foreign.name];
}
}
}
}
return ex;
}