(symbolTable ast.SymbolTable, parent *ast.Symbol, node *ast.Node, includes ast.SymbolFlags, excludes ast.SymbolFlags, isReplaceableByMethod bool, isComputedName bool)
| 152 | } |
| 153 | |
| 154 | func (b *Binder) declareSymbolEx(symbolTable ast.SymbolTable, parent *ast.Symbol, node *ast.Node, includes ast.SymbolFlags, excludes ast.SymbolFlags, isReplaceableByMethod bool, isComputedName bool) *ast.Symbol { |
| 155 | debug.Assert(isComputedName || !ast.HasDynamicName(node)) |
| 156 | isDefaultExport := ast.HasSyntacticModifier(node, ast.ModifierFlagsDefault) || ast.IsExportSpecifier(node) && ast.ModuleExportNameIsDefault(node.AsExportSpecifier().Name()) |
| 157 | // The exported symbol for an export default function/class node is always named "default" |
| 158 | var name string |
| 159 | switch { |
| 160 | case isComputedName: |
| 161 | name = ast.InternalSymbolNameComputed |
| 162 | case isDefaultExport && parent != nil: |
| 163 | name = ast.InternalSymbolNameDefault |
| 164 | default: |
| 165 | name = b.getDeclarationName(node) |
| 166 | } |
| 167 | var symbol *ast.Symbol |
| 168 | if name == ast.InternalSymbolNameMissing { |
| 169 | symbol = b.newSymbol(ast.SymbolFlagsNone, ast.InternalSymbolNameMissing) |
| 170 | } else { |
| 171 | // Check and see if the symbol table already has a symbol with this name. If not, |
| 172 | // create a new symbol with this name and add it to the table. Note that we don't |
| 173 | // give the new symbol any flags *yet*. This ensures that it will not conflict |
| 174 | // with the 'excludes' flags we pass in. |
| 175 | // |
| 176 | // If we do get an existing symbol, see if it conflicts with the new symbol we're |
| 177 | // creating. For example, a 'var' symbol and a 'class' symbol will conflict within |
| 178 | // the same symbol table. If we have a conflict, report the issue on each |
| 179 | // declaration we have for this symbol, and then create a new symbol for this |
| 180 | // declaration. |
| 181 | // |
| 182 | // Note that when properties declared in Javascript constructors |
| 183 | // (marked by isReplaceableByMethod) conflict with another symbol, the property loses. |
| 184 | // Always. This allows the common Javascript pattern of overwriting a prototype method |
| 185 | // with an bound instance method of the same type: `this.method = this.method.bind(this)` |
| 186 | // |
| 187 | // If we created a new symbol, either because we didn't have a symbol with this name |
| 188 | // in the symbol table, or we conflicted with an existing symbol, then just add this |
| 189 | // node as the sole declaration of the new symbol. |
| 190 | // |
| 191 | // Otherwise, we'll be merging into a compatible existing symbol (for example when |
| 192 | // you have multiple 'vars' with the same name in the same container). In this case |
| 193 | // just add this node into the declarations list of the symbol. |
| 194 | symbol = symbolTable[name] |
| 195 | if includes&ast.SymbolFlagsClassifiable != 0 { |
| 196 | b.classifiableNames.Add(name) |
| 197 | } |
| 198 | if symbol == nil { |
| 199 | symbol = b.newSymbol(ast.SymbolFlagsNone, name) |
| 200 | symbolTable[name] = symbol |
| 201 | if isReplaceableByMethod { |
| 202 | symbol.Flags |= ast.SymbolFlagsReplaceableByMethod |
| 203 | } |
| 204 | } else if isReplaceableByMethod && symbol.Flags&ast.SymbolFlagsReplaceableByMethod == 0 { |
| 205 | // A symbol already exists, so don't add this as a declaration. |
| 206 | return symbol |
| 207 | } else if symbol.Flags&excludes != 0 { |
| 208 | if symbol.Flags&ast.SymbolFlagsReplaceableByMethod != 0 { |
| 209 | // Javascript constructor-declared symbols can be discarded in favor of |
| 210 | // prototype symbols like methods. |
| 211 | symbol = b.newSymbol(ast.SymbolFlagsNone, name) |
no test coverage detected