|  | // Copyright 2021 The Tint Authors. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #include "src/tint/transform/unshadow.h" | 
|  |  | 
|  | #include <memory> | 
|  | #include <unordered_map> | 
|  | #include <utility> | 
|  |  | 
|  | #include "src/tint/program_builder.h" | 
|  | #include "src/tint/sem/block_statement.h" | 
|  | #include "src/tint/sem/function.h" | 
|  | #include "src/tint/sem/statement.h" | 
|  | #include "src/tint/sem/variable.h" | 
|  |  | 
|  | TINT_INSTANTIATE_TYPEINFO(tint::transform::Unshadow); | 
|  |  | 
|  | namespace tint::transform { | 
|  |  | 
|  | /// The PIMPL state for the Unshadow transform | 
|  | struct Unshadow::State { | 
|  | /// The clone context | 
|  | CloneContext& ctx; | 
|  |  | 
|  | /// Constructor | 
|  | /// @param context the clone context | 
|  | explicit State(CloneContext& context) : ctx(context) {} | 
|  |  | 
|  | /// Performs the transformation | 
|  | void Run() { | 
|  | auto& sem = ctx.src->Sem(); | 
|  |  | 
|  | // Maps a variable to its new name. | 
|  | std::unordered_map<const sem::Variable*, Symbol> renamed_to; | 
|  |  | 
|  | auto rename = [&](const sem::Variable* v) -> const ast::Variable* { | 
|  | auto* decl = v->Declaration(); | 
|  | auto name = ctx.src->Symbols().NameFor(decl->symbol); | 
|  | auto symbol = ctx.dst->Symbols().New(name); | 
|  | renamed_to.emplace(v, symbol); | 
|  |  | 
|  | auto source = ctx.Clone(decl->source); | 
|  | auto* type = ctx.Clone(decl->type); | 
|  | auto* constructor = ctx.Clone(decl->constructor); | 
|  | auto attributes = ctx.Clone(decl->attributes); | 
|  | return Switch( | 
|  | decl,  // | 
|  | [&](const ast::Var* var) { | 
|  | return ctx.dst->Var(source, symbol, type, var->declared_storage_class, | 
|  | var->declared_access, constructor, attributes); | 
|  | }, | 
|  | [&](const ast::Let*) { | 
|  | return ctx.dst->Let(source, symbol, type, constructor, attributes); | 
|  | }, | 
|  | [&](const ast::Const*) { | 
|  | return ctx.dst->Const(source, symbol, type, constructor, attributes); | 
|  | }, | 
|  | [&](const ast::Parameter*) { | 
|  | return ctx.dst->Param(source, symbol, type, attributes); | 
|  | }, | 
|  | [&](Default) { | 
|  | TINT_ICE(Transform, ctx.dst->Diagnostics()) | 
|  | << "unexpected variable type: " << decl->TypeInfo().name; | 
|  | return nullptr; | 
|  | }); | 
|  | }; | 
|  |  | 
|  | ctx.ReplaceAll([&](const ast::Variable* v) -> const ast::Variable* { | 
|  | if (auto* local = sem.Get<sem::LocalVariable>(v)) { | 
|  | if (local->Shadows()) { | 
|  | return rename(local); | 
|  | } | 
|  | } | 
|  | if (auto* param = sem.Get<sem::Parameter>(v)) { | 
|  | if (param->Shadows()) { | 
|  | return rename(param); | 
|  | } | 
|  | } | 
|  | return nullptr; | 
|  | }); | 
|  | ctx.ReplaceAll( | 
|  | [&](const ast::IdentifierExpression* ident) -> const tint::ast::IdentifierExpression* { | 
|  | if (auto* user = sem.Get<sem::VariableUser>(ident)) { | 
|  | auto it = renamed_to.find(user->Variable()); | 
|  | if (it != renamed_to.end()) { | 
|  | return ctx.dst->Expr(it->second); | 
|  | } | 
|  | } | 
|  | return nullptr; | 
|  | }); | 
|  | ctx.Clone(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | Unshadow::Unshadow() = default; | 
|  |  | 
|  | Unshadow::~Unshadow() = default; | 
|  |  | 
|  | void Unshadow::Run(CloneContext& ctx, const DataMap&, DataMap&) const { | 
|  | State(ctx).Run(); | 
|  | } | 
|  |  | 
|  | }  // namespace tint::transform |