| // 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 |