• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "fuzzers/tint_ast_fuzzer/mutations/replace_identifier.h"
16 
17 #include <utility>
18 
19 #include "fuzzers/tint_ast_fuzzer/util.h"
20 #include "src/program_builder.h"
21 
22 namespace tint {
23 namespace fuzzers {
24 namespace ast_fuzzer {
25 
MutationReplaceIdentifier(protobufs::MutationReplaceIdentifier message)26 MutationReplaceIdentifier::MutationReplaceIdentifier(
27     protobufs::MutationReplaceIdentifier message)
28     : message_(std::move(message)) {}
29 
MutationReplaceIdentifier(uint32_t use_id,uint32_t replacement_id)30 MutationReplaceIdentifier::MutationReplaceIdentifier(uint32_t use_id,
31                                                      uint32_t replacement_id) {
32   message_.set_use_id(use_id);
33   message_.set_replacement_id(replacement_id);
34 }
35 
IsApplicable(const tint::Program & program,const NodeIdMap & node_id_map) const36 bool MutationReplaceIdentifier::IsApplicable(
37     const tint::Program& program,
38     const NodeIdMap& node_id_map) const {
39   const auto* use_ast_node = tint::As<ast::IdentifierExpression>(
40       node_id_map.GetNode(message_.use_id()));
41   if (!use_ast_node) {
42     // Either the `use_id` is invalid or the node is not an
43     // `IdentifierExpression`.
44     return false;
45   }
46 
47   const auto* use_sem_node =
48       tint::As<sem::VariableUser>(program.Sem().Get(use_ast_node));
49   if (!use_sem_node) {
50     // Either the semantic information is not present for a `use_node` or that
51     // node is not a variable user.
52     return false;
53   }
54 
55   const auto* replacement_ast_node =
56       tint::As<ast::Variable>(node_id_map.GetNode(message_.replacement_id()));
57   if (!replacement_ast_node) {
58     // Either the `replacement_id` is invalid or is not an id of a variable.
59     return false;
60   }
61 
62   const auto* replacement_sem_node = program.Sem().Get(replacement_ast_node);
63   if (!replacement_sem_node) {
64     return false;
65   }
66 
67   if (replacement_sem_node == use_sem_node->Variable()) {
68     return false;
69   }
70 
71   auto in_scope =
72       util::GetAllVarsInScope(program, use_sem_node->Stmt(),
73                               [replacement_sem_node](const sem::Variable* var) {
74                                 return var == replacement_sem_node;
75                               });
76   if (in_scope.empty()) {
77     // The replacement variable is not in scope.
78     return false;
79   }
80 
81   return use_sem_node->Type() == replacement_sem_node->Type();
82 }
83 
Apply(const NodeIdMap & node_id_map,tint::CloneContext * clone_context,NodeIdMap * new_node_id_map) const84 void MutationReplaceIdentifier::Apply(const NodeIdMap& node_id_map,
85                                       tint::CloneContext* clone_context,
86                                       NodeIdMap* new_node_id_map) const {
87   const auto* use_node = node_id_map.GetNode(message_.use_id());
88   const auto* replacement_var =
89       tint::As<ast::Variable>(node_id_map.GetNode(message_.replacement_id()));
90 
91   auto* cloned_replacement =
92       clone_context->dst->Expr(clone_context->Clone(use_node->source),
93                                clone_context->Clone(replacement_var->symbol));
94   clone_context->Replace(use_node, cloned_replacement);
95   new_node_id_map->Add(cloned_replacement, message_.use_id());
96 }
97 
ToMessage() const98 protobufs::Mutation MutationReplaceIdentifier::ToMessage() const {
99   protobufs::Mutation mutation;
100   *mutation.mutable_replace_identifier() = message_;
101   return mutation;
102 }
103 
104 }  // namespace ast_fuzzer
105 }  // namespace fuzzers
106 }  // namespace tint
107