• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 #include "compiler/translator/ValidateAST.h"
8 
9 #include "compiler/translator/Diagnostics.h"
10 #include "compiler/translator/tree_util/IntermTraverse.h"
11 
12 namespace sh
13 {
14 
15 namespace
16 {
17 
18 class ValidateAST : public TIntermTraverser
19 {
20   public:
21     static bool validate(TIntermNode *root,
22                          TDiagnostics *diagnostics,
23                          const ValidateASTOptions &options);
24 
25     void visitSymbol(TIntermSymbol *node) override;
26     void visitConstantUnion(TIntermConstantUnion *node) override;
27     bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
28     bool visitBinary(Visit visit, TIntermBinary *node) override;
29     bool visitUnary(Visit visit, TIntermUnary *node) override;
30     bool visitTernary(Visit visit, TIntermTernary *node) override;
31     bool visitIfElse(Visit visit, TIntermIfElse *node) override;
32     bool visitSwitch(Visit visit, TIntermSwitch *node) override;
33     bool visitCase(Visit visit, TIntermCase *node) override;
34     void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
35     bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
36     bool visitAggregate(Visit visit, TIntermAggregate *node) override;
37     bool visitBlock(Visit visit, TIntermBlock *node) override;
38     bool visitGlobalQualifierDeclaration(Visit visit,
39                                          TIntermGlobalQualifierDeclaration *node) override;
40     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
41     bool visitLoop(Visit visit, TIntermLoop *node) override;
42     bool visitBranch(Visit visit, TIntermBranch *node) override;
43     void visitPreprocessorDirective(TIntermPreprocessorDirective *node) override;
44 
45   private:
46     ValidateAST(TIntermNode *root, TDiagnostics *diagnostics, const ValidateASTOptions &options);
47 
48     // Visit as a generic node
49     void visitNode(Visit visit, TIntermNode *node);
50 
51     void expectNonNullChildren(Visit visit, TIntermNode *node, size_t least_count);
52 
53     bool validateInternal();
54 
55     ValidateASTOptions mOptions;
56     TDiagnostics *mDiagnostics;
57 
58     // For validateSingleParent:
59     std::map<TIntermNode *, TIntermNode *> mParent;
60     bool mSingleParentFailed = false;
61 
62     // For validateNullNodes
63     bool mNullNodesFailed = false;
64 };
65 
validate(TIntermNode * root,TDiagnostics * diagnostics,const ValidateASTOptions & options)66 bool ValidateAST::validate(TIntermNode *root,
67                            TDiagnostics *diagnostics,
68                            const ValidateASTOptions &options)
69 {
70     ValidateAST validate(root, diagnostics, options);
71     root->traverse(&validate);
72     return validate.validateInternal();
73 }
74 
ValidateAST(TIntermNode * root,TDiagnostics * diagnostics,const ValidateASTOptions & options)75 ValidateAST::ValidateAST(TIntermNode *root,
76                          TDiagnostics *diagnostics,
77                          const ValidateASTOptions &options)
78     : TIntermTraverser(true, false, true, nullptr), mOptions(options), mDiagnostics(diagnostics)
79 {
80     if (mOptions.validateSingleParent)
81     {
82         mParent[root] = nullptr;
83     }
84 }
85 
visitNode(Visit visit,TIntermNode * node)86 void ValidateAST::visitNode(Visit visit, TIntermNode *node)
87 {
88     if (visit == PreVisit && mOptions.validateSingleParent)
89     {
90         size_t childCount = node->getChildCount();
91         for (size_t i = 0; i < childCount; ++i)
92         {
93             TIntermNode *child = node->getChildNode(i);
94             if (mParent.find(child) != mParent.end())
95             {
96                 // If child is visited twice but through the same parent, the problem is in one of
97                 // the ancestors.
98                 if (mParent[child] != node)
99                 {
100                     mDiagnostics->error(node->getLine(), "Found child with two parents",
101                                         "<validateSingleParent>");
102                     mSingleParentFailed = true;
103                 }
104             }
105 
106             mParent[child] = node;
107         }
108     }
109 }
110 
expectNonNullChildren(Visit visit,TIntermNode * node,size_t least_count)111 void ValidateAST::expectNonNullChildren(Visit visit, TIntermNode *node, size_t least_count)
112 {
113     if (visit == PreVisit && mOptions.validateNullNodes)
114     {
115         size_t childCount = node->getChildCount();
116         if (childCount < least_count)
117         {
118             mDiagnostics->error(node->getLine(), "Too few children", "<validateNullNodes>");
119             mNullNodesFailed = true;
120         }
121 
122         for (size_t i = 0; i < childCount; ++i)
123         {
124             if (node->getChildNode(i) == nullptr)
125             {
126                 mDiagnostics->error(node->getLine(), "Found nullptr child", "<validateNullNodes>");
127                 mNullNodesFailed = true;
128             }
129         }
130     }
131 }
132 
visitSymbol(TIntermSymbol * node)133 void ValidateAST::visitSymbol(TIntermSymbol *node)
134 {
135     visitNode(PreVisit, node);
136 }
137 
visitConstantUnion(TIntermConstantUnion * node)138 void ValidateAST::visitConstantUnion(TIntermConstantUnion *node)
139 {
140     visitNode(PreVisit, node);
141 }
142 
visitSwizzle(Visit visit,TIntermSwizzle * node)143 bool ValidateAST::visitSwizzle(Visit visit, TIntermSwizzle *node)
144 {
145     visitNode(visit, node);
146     return true;
147 }
148 
visitBinary(Visit visit,TIntermBinary * node)149 bool ValidateAST::visitBinary(Visit visit, TIntermBinary *node)
150 {
151     visitNode(visit, node);
152     return true;
153 }
154 
visitUnary(Visit visit,TIntermUnary * node)155 bool ValidateAST::visitUnary(Visit visit, TIntermUnary *node)
156 {
157     visitNode(visit, node);
158     return true;
159 }
160 
visitTernary(Visit visit,TIntermTernary * node)161 bool ValidateAST::visitTernary(Visit visit, TIntermTernary *node)
162 {
163     visitNode(visit, node);
164     return true;
165 }
166 
visitIfElse(Visit visit,TIntermIfElse * node)167 bool ValidateAST::visitIfElse(Visit visit, TIntermIfElse *node)
168 {
169     visitNode(visit, node);
170     return true;
171 }
172 
visitSwitch(Visit visit,TIntermSwitch * node)173 bool ValidateAST::visitSwitch(Visit visit, TIntermSwitch *node)
174 {
175     visitNode(visit, node);
176     return true;
177 }
178 
visitCase(Visit visit,TIntermCase * node)179 bool ValidateAST::visitCase(Visit visit, TIntermCase *node)
180 {
181     visitNode(visit, node);
182     return true;
183 }
184 
visitFunctionPrototype(TIntermFunctionPrototype * node)185 void ValidateAST::visitFunctionPrototype(TIntermFunctionPrototype *node)
186 {
187     visitNode(PreVisit, node);
188 }
189 
visitFunctionDefinition(Visit visit,TIntermFunctionDefinition * node)190 bool ValidateAST::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
191 {
192     visitNode(visit, node);
193     return true;
194 }
195 
visitAggregate(Visit visit,TIntermAggregate * node)196 bool ValidateAST::visitAggregate(Visit visit, TIntermAggregate *node)
197 {
198     visitNode(visit, node);
199     expectNonNullChildren(visit, node, 0);
200     return true;
201 }
202 
visitBlock(Visit visit,TIntermBlock * node)203 bool ValidateAST::visitBlock(Visit visit, TIntermBlock *node)
204 {
205     visitNode(visit, node);
206     expectNonNullChildren(visit, node, 0);
207     return true;
208 }
209 
visitGlobalQualifierDeclaration(Visit visit,TIntermGlobalQualifierDeclaration * node)210 bool ValidateAST::visitGlobalQualifierDeclaration(Visit visit,
211                                                   TIntermGlobalQualifierDeclaration *node)
212 {
213     visitNode(visit, node);
214     return true;
215 }
216 
visitDeclaration(Visit visit,TIntermDeclaration * node)217 bool ValidateAST::visitDeclaration(Visit visit, TIntermDeclaration *node)
218 {
219     visitNode(visit, node);
220     expectNonNullChildren(visit, node, 0);
221     return true;
222 }
223 
visitLoop(Visit visit,TIntermLoop * node)224 bool ValidateAST::visitLoop(Visit visit, TIntermLoop *node)
225 {
226     visitNode(visit, node);
227     return true;
228 }
229 
visitBranch(Visit visit,TIntermBranch * node)230 bool ValidateAST::visitBranch(Visit visit, TIntermBranch *node)
231 {
232     visitNode(visit, node);
233     return true;
234 }
235 
visitPreprocessorDirective(TIntermPreprocessorDirective * node)236 void ValidateAST::visitPreprocessorDirective(TIntermPreprocessorDirective *node)
237 {
238     visitNode(PreVisit, node);
239 }
240 
validateInternal()241 bool ValidateAST::validateInternal()
242 {
243     return !mSingleParentFailed && !mNullNodesFailed;
244 }
245 
246 }  // anonymous namespace
247 
ValidateAST(TIntermNode * root,TDiagnostics * diagnostics,const ValidateASTOptions & options)248 bool ValidateAST(TIntermNode *root, TDiagnostics *diagnostics, const ValidateASTOptions &options)
249 {
250     return ValidateAST::validate(root, diagnostics, options);
251 }
252 
253 }  // namespace sh
254