Solidity: ImportDirective symbolAliases are not pointing to external nodes

Created on 20 Nov 2019  路  1Comment  路  Source: ethereum/solidity

Hey, everyone. Was recently working with SolcJS AST and noticed something strange, what I would really like to ask about.

  • external.sol
contract A {}
  • current.sol
pragma solidity 0.5.12;

import {A as X, A as Y} from "./external.sol";

contract Z is X {}

By compiling current.sol with solc-js 0.5.12 I'm getting following ImportDirective AST node:

  • compact:
{
    "absolutePath": "../external.sol",
    "file": "./external.sol",
    "id": 4,
    "nodeType": "ImportDirective",
    "scope": 8,
    "sourceUnit": 10,
    "src": "25:46:0",
    "symbolAliases": [
        {
            "foreign": 2,
            "local": "X"
        },
        {
            "foreign": 3,
            "local": "Y"
        }
    ],
    "unitAlias": ""
}
  • legacy:
{
    "attributes": {
        "SourceUnit": 10,
        "absolutePath": "../external.sol",
        "file": "./external.sol",
        "scope": 8,
        "symbolAliases": [
            {
                "foreign": 2,
                "local": "X"
            },
            {
                "foreign": 3,
                "local": "Y"
            }
        ],
        "unitAlias": ""
    },
    "id": 4,
    "name": "ImportDirective",
    "src": "25:46:0"
}

I was expecting that symbolAliases will contain foreign property to point to external declaration of contract A, but it actually is pointing to nowhere (there is no nodes with ID = 2 or ID = 3). Also, there is an ID gap between PragmaDirective (ID = 1) and sequentially following node ImportDirective (ID = 4), which maybe gives an idea that there is something off here...

Is foreign referencing external declarations by some another way (and I'm missing something here)? Shouldn't it have value of referenced contract declaration node id (9) instead (like UserDefinedTypeName does)?

{
    "contractScope": null,
    "id": 5,
    "name": "X",
    "nodeType": "UserDefinedTypeName",
    "referencedDeclaration": 9,
    "src": "87:1:0",
    "typeDescriptions": {
        "typeIdentifier": "t_contract$_A_$9",
        "typeString": "contract A"
    }
}

Thanks for clarification and your time. Regards.

bug

Most helpful comment

You are completely right with your assumptions. The foreign part is simply missing here.
Lucky for you we already fixed that in the upcoming release 0.6.0 (any day now).

The new output looks like this:

======= current.sol =======
{
  "absolutePath": "current.sol",
  "exportedSymbols":
  {
    "Z":
    [
      6
    ]
  },
  "id": 7,
  "nodeType": "SourceUnit",
  "nodes":
  [
    {
      "absolutePath": "external.sol",
      "file": "./external.sol",
      "id": 3,
      "nodeType": "ImportDirective",
      "scope": 7,
      "sourceUnit": 9,
      "src": "0:46:0",
      "symbolAliases":
      [
        {
          "foreign":
          {
            "argumentTypes": null,
            "id": 1,
            "name": "A",
            "nodeType": "Identifier",
            "overloadedDeclarations": [],
            "referencedDeclaration": null,
            "src": "8:1:0",
            "typeDescriptions":
            {
              "typeIdentifier": null,
              "typeString": null
            }
          },
          "local": "X"
        },
        {
          "foreign":
          {
            "argumentTypes": null,
            "id": 2,
            "name": "A",
            "nodeType": "Identifier",
            "overloadedDeclarations": [],
            "referencedDeclaration": null,
            "src": "16:1:0",
            "typeDescriptions":
            {
              "typeIdentifier": null,
              "typeString": null
            }
          },
          "local": "Y"
        }
      ],
      "unitAlias": ""
    },
    {
      "abstract": false,
      "baseContracts":
      [
        {
          "arguments": null,
          "baseName":
          {
            "contractScope": null,
            "id": 4,
            "name": "X",
            "nodeType": "UserDefinedTypeName",
            "referencedDeclaration": 8,
            "src": "62:1:0",
            "typeDescriptions":
            {
              "typeIdentifier": "t_contract$_A_$8",
              "typeString": "contract A"
            }
          },
          "id": 5,
          "nodeType": "InheritanceSpecifier",
          "src": "62:1:0"
        }
      ],
      "contractDependencies":
      [
        8
      ],
      "contractKind": "contract",
      "documentation": null,
      "fullyImplemented": true,
      "id": 6,
      "linearizedBaseContracts":
      [
        6,
        8
      ],
      "name": "Z",
      "nodeType": "ContractDefinition",
      "nodes": [],
      "scope": 7,
      "src": "48:18:0"
    }
  ],
  "src": "0:67:0"
}
======= external.sol =======
{
  "absolutePath": "external.sol",
  "exportedSymbols":
  {
    "A":
    [
      8
    ]
  },
  "id": 9,
  "nodeType": "SourceUnit",
  "nodes":
  [
    {
      "abstract": false,
      "baseContracts": [],
      "contractDependencies": [],
      "contractKind": "contract",
      "documentation": null,
      "fullyImplemented": true,
      "id": 8,
      "linearizedBaseContracts":
      [
        8
      ],
      "name": "A",
      "nodeType": "ContractDefinition",
      "nodes": [],
      "scope": 9,
      "src": "0:13:1"
    }
  ],
  "src": "0:14:1"
}

Feel free to reopen this if you still think the output is not correct.

>All comments

You are completely right with your assumptions. The foreign part is simply missing here.
Lucky for you we already fixed that in the upcoming release 0.6.0 (any day now).

The new output looks like this:

======= current.sol =======
{
  "absolutePath": "current.sol",
  "exportedSymbols":
  {
    "Z":
    [
      6
    ]
  },
  "id": 7,
  "nodeType": "SourceUnit",
  "nodes":
  [
    {
      "absolutePath": "external.sol",
      "file": "./external.sol",
      "id": 3,
      "nodeType": "ImportDirective",
      "scope": 7,
      "sourceUnit": 9,
      "src": "0:46:0",
      "symbolAliases":
      [
        {
          "foreign":
          {
            "argumentTypes": null,
            "id": 1,
            "name": "A",
            "nodeType": "Identifier",
            "overloadedDeclarations": [],
            "referencedDeclaration": null,
            "src": "8:1:0",
            "typeDescriptions":
            {
              "typeIdentifier": null,
              "typeString": null
            }
          },
          "local": "X"
        },
        {
          "foreign":
          {
            "argumentTypes": null,
            "id": 2,
            "name": "A",
            "nodeType": "Identifier",
            "overloadedDeclarations": [],
            "referencedDeclaration": null,
            "src": "16:1:0",
            "typeDescriptions":
            {
              "typeIdentifier": null,
              "typeString": null
            }
          },
          "local": "Y"
        }
      ],
      "unitAlias": ""
    },
    {
      "abstract": false,
      "baseContracts":
      [
        {
          "arguments": null,
          "baseName":
          {
            "contractScope": null,
            "id": 4,
            "name": "X",
            "nodeType": "UserDefinedTypeName",
            "referencedDeclaration": 8,
            "src": "62:1:0",
            "typeDescriptions":
            {
              "typeIdentifier": "t_contract$_A_$8",
              "typeString": "contract A"
            }
          },
          "id": 5,
          "nodeType": "InheritanceSpecifier",
          "src": "62:1:0"
        }
      ],
      "contractDependencies":
      [
        8
      ],
      "contractKind": "contract",
      "documentation": null,
      "fullyImplemented": true,
      "id": 6,
      "linearizedBaseContracts":
      [
        6,
        8
      ],
      "name": "Z",
      "nodeType": "ContractDefinition",
      "nodes": [],
      "scope": 7,
      "src": "48:18:0"
    }
  ],
  "src": "0:67:0"
}
======= external.sol =======
{
  "absolutePath": "external.sol",
  "exportedSymbols":
  {
    "A":
    [
      8
    ]
  },
  "id": 9,
  "nodeType": "SourceUnit",
  "nodes":
  [
    {
      "abstract": false,
      "baseContracts": [],
      "contractDependencies": [],
      "contractKind": "contract",
      "documentation": null,
      "fullyImplemented": true,
      "id": 8,
      "linearizedBaseContracts":
      [
        8
      ],
      "name": "A",
      "nodeType": "ContractDefinition",
      "nodes": [],
      "scope": 9,
      "src": "0:13:1"
    }
  ],
  "src": "0:14:1"
}

Feel free to reopen this if you still think the output is not correct.

Was this page helpful?
0 / 5 - 0 ratings