xref: /aosp_15_r20/external/angle/src/compiler/translator/ValidateAST.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker 
7*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/ValidateAST.h"
8*8975f5c5SAndroid Build Coastguard Worker 
9*8975f5c5SAndroid Build Coastguard Worker #include "common/utilities.h"
10*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/Diagnostics.h"
11*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/ImmutableStringBuilder.h"
12*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/Name.h"
13*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/Symbol.h"
14*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/tree_util/IntermTraverse.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/tree_util/SpecializationConstant.h"
16*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/util.h"
17*8975f5c5SAndroid Build Coastguard Worker 
18*8975f5c5SAndroid Build Coastguard Worker namespace sh
19*8975f5c5SAndroid Build Coastguard Worker {
20*8975f5c5SAndroid Build Coastguard Worker 
21*8975f5c5SAndroid Build Coastguard Worker namespace
22*8975f5c5SAndroid Build Coastguard Worker {
23*8975f5c5SAndroid Build Coastguard Worker 
24*8975f5c5SAndroid Build Coastguard Worker class ValidateAST : public TIntermTraverser
25*8975f5c5SAndroid Build Coastguard Worker {
26*8975f5c5SAndroid Build Coastguard Worker   public:
27*8975f5c5SAndroid Build Coastguard Worker     static bool validate(TIntermNode *root,
28*8975f5c5SAndroid Build Coastguard Worker                          TDiagnostics *diagnostics,
29*8975f5c5SAndroid Build Coastguard Worker                          const ValidateASTOptions &options);
30*8975f5c5SAndroid Build Coastguard Worker 
31*8975f5c5SAndroid Build Coastguard Worker     void visitSymbol(TIntermSymbol *node) override;
32*8975f5c5SAndroid Build Coastguard Worker     void visitConstantUnion(TIntermConstantUnion *node) override;
33*8975f5c5SAndroid Build Coastguard Worker     bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
34*8975f5c5SAndroid Build Coastguard Worker     bool visitBinary(Visit visit, TIntermBinary *node) override;
35*8975f5c5SAndroid Build Coastguard Worker     bool visitUnary(Visit visit, TIntermUnary *node) override;
36*8975f5c5SAndroid Build Coastguard Worker     bool visitTernary(Visit visit, TIntermTernary *node) override;
37*8975f5c5SAndroid Build Coastguard Worker     bool visitIfElse(Visit visit, TIntermIfElse *node) override;
38*8975f5c5SAndroid Build Coastguard Worker     bool visitSwitch(Visit visit, TIntermSwitch *node) override;
39*8975f5c5SAndroid Build Coastguard Worker     bool visitCase(Visit visit, TIntermCase *node) override;
40*8975f5c5SAndroid Build Coastguard Worker     void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
41*8975f5c5SAndroid Build Coastguard Worker     bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
42*8975f5c5SAndroid Build Coastguard Worker     bool visitAggregate(Visit visit, TIntermAggregate *node) override;
43*8975f5c5SAndroid Build Coastguard Worker     bool visitBlock(Visit visit, TIntermBlock *node) override;
44*8975f5c5SAndroid Build Coastguard Worker     bool visitGlobalQualifierDeclaration(Visit visit,
45*8975f5c5SAndroid Build Coastguard Worker                                          TIntermGlobalQualifierDeclaration *node) override;
46*8975f5c5SAndroid Build Coastguard Worker     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
47*8975f5c5SAndroid Build Coastguard Worker     bool visitLoop(Visit visit, TIntermLoop *node) override;
48*8975f5c5SAndroid Build Coastguard Worker     bool visitBranch(Visit visit, TIntermBranch *node) override;
49*8975f5c5SAndroid Build Coastguard Worker     void visitPreprocessorDirective(TIntermPreprocessorDirective *node) override;
50*8975f5c5SAndroid Build Coastguard Worker 
51*8975f5c5SAndroid Build Coastguard Worker   private:
52*8975f5c5SAndroid Build Coastguard Worker     ValidateAST(TIntermNode *root, TDiagnostics *diagnostics, const ValidateASTOptions &options);
53*8975f5c5SAndroid Build Coastguard Worker 
54*8975f5c5SAndroid Build Coastguard Worker     // Visit as a generic node
55*8975f5c5SAndroid Build Coastguard Worker     void visitNode(Visit visit, TIntermNode *node);
56*8975f5c5SAndroid Build Coastguard Worker     // Visit a structure or interface block, and recursively visit its fields of structure type.
57*8975f5c5SAndroid Build Coastguard Worker     void visitStructOrInterfaceBlockDeclaration(const TType &type, const TSourceLoc &location);
58*8975f5c5SAndroid Build Coastguard Worker     void visitStructUsage(const TType &type, const TSourceLoc &location);
59*8975f5c5SAndroid Build Coastguard Worker     // Visit a unary or aggregate node and validate its built-in op against its built-in function.
60*8975f5c5SAndroid Build Coastguard Worker     void visitBuiltInFunction(TIntermOperator *op, const TFunction *function);
61*8975f5c5SAndroid Build Coastguard Worker     // Visit an aggregate node and validate its function call is to one that's already defined.
62*8975f5c5SAndroid Build Coastguard Worker     void visitFunctionCall(TIntermAggregate *node);
63*8975f5c5SAndroid Build Coastguard Worker     // Visit a binary node and validate its type against its operands.
64*8975f5c5SAndroid Build Coastguard Worker     void validateExpressionTypeBinary(TIntermBinary *node);
65*8975f5c5SAndroid Build Coastguard Worker     // Visit a switch node and validate its selector type is integer.
66*8975f5c5SAndroid Build Coastguard Worker     void validateExpressionTypeSwitch(TIntermSwitch *node);
67*8975f5c5SAndroid Build Coastguard Worker     // Visit a symbol node and validate it's declared previously.
68*8975f5c5SAndroid Build Coastguard Worker     void visitVariableNeedingDeclaration(TIntermSymbol *node);
69*8975f5c5SAndroid Build Coastguard Worker     // Visit a built-in symbol node and validate it's consistently used across the tree.
70*8975f5c5SAndroid Build Coastguard Worker     void visitBuiltInVariable(TIntermSymbol *node);
71*8975f5c5SAndroid Build Coastguard Worker 
72*8975f5c5SAndroid Build Coastguard Worker     void scope(Visit visit);
73*8975f5c5SAndroid Build Coastguard Worker     bool isVariableDeclared(const TVariable *variable);
74*8975f5c5SAndroid Build Coastguard Worker     bool variableNeedsDeclaration(const TVariable *variable);
75*8975f5c5SAndroid Build Coastguard Worker     const TFieldListCollection *getStructOrInterfaceBlock(const TType &type, Name *typeNameOut);
76*8975f5c5SAndroid Build Coastguard Worker 
77*8975f5c5SAndroid Build Coastguard Worker     void expectNonNullChildren(Visit visit, TIntermNode *node, size_t least_count);
78*8975f5c5SAndroid Build Coastguard Worker 
79*8975f5c5SAndroid Build Coastguard Worker     bool validateInternal();
80*8975f5c5SAndroid Build Coastguard Worker     bool isInDeclaration() const;
81*8975f5c5SAndroid Build Coastguard Worker 
82*8975f5c5SAndroid Build Coastguard Worker     ValidateASTOptions mOptions;
83*8975f5c5SAndroid Build Coastguard Worker     TDiagnostics *mDiagnostics;
84*8975f5c5SAndroid Build Coastguard Worker 
85*8975f5c5SAndroid Build Coastguard Worker     // For validateSingleParent:
86*8975f5c5SAndroid Build Coastguard Worker     std::map<TIntermNode *, TIntermNode *> mParent;
87*8975f5c5SAndroid Build Coastguard Worker     bool mSingleParentFailed = false;
88*8975f5c5SAndroid Build Coastguard Worker 
89*8975f5c5SAndroid Build Coastguard Worker     // For validateVariableReferences:
90*8975f5c5SAndroid Build Coastguard Worker     std::vector<std::set<const TVariable *>> mDeclaredVariables;
91*8975f5c5SAndroid Build Coastguard Worker     std::set<const TInterfaceBlock *> mNamelessInterfaceBlocks;
92*8975f5c5SAndroid Build Coastguard Worker     std::map<ImmutableString, const TVariable *> mReferencedBuiltIns;
93*8975f5c5SAndroid Build Coastguard Worker     bool mVariableReferencesFailed = false;
94*8975f5c5SAndroid Build Coastguard Worker 
95*8975f5c5SAndroid Build Coastguard Worker     // For validateOps:
96*8975f5c5SAndroid Build Coastguard Worker     bool mOpsFailed = false;
97*8975f5c5SAndroid Build Coastguard Worker 
98*8975f5c5SAndroid Build Coastguard Worker     // For validateBuiltInOps:
99*8975f5c5SAndroid Build Coastguard Worker     bool mBuiltInOpsFailed = false;
100*8975f5c5SAndroid Build Coastguard Worker 
101*8975f5c5SAndroid Build Coastguard Worker     // For validateFunctionCall:
102*8975f5c5SAndroid Build Coastguard Worker     std::set<const TFunction *> mDeclaredFunctions;
103*8975f5c5SAndroid Build Coastguard Worker     bool mFunctionCallFailed = false;
104*8975f5c5SAndroid Build Coastguard Worker 
105*8975f5c5SAndroid Build Coastguard Worker     // For validateNoRawFunctionCalls:
106*8975f5c5SAndroid Build Coastguard Worker     bool mNoRawFunctionCallsFailed = false;
107*8975f5c5SAndroid Build Coastguard Worker 
108*8975f5c5SAndroid Build Coastguard Worker     // For validateNullNodes:
109*8975f5c5SAndroid Build Coastguard Worker     bool mNullNodesFailed = false;
110*8975f5c5SAndroid Build Coastguard Worker 
111*8975f5c5SAndroid Build Coastguard Worker     // For validateQualifiers:
112*8975f5c5SAndroid Build Coastguard Worker     bool mQualifiersFailed = false;
113*8975f5c5SAndroid Build Coastguard Worker 
114*8975f5c5SAndroid Build Coastguard Worker     // For validatePrecision:
115*8975f5c5SAndroid Build Coastguard Worker     bool mPrecisionFailed = false;
116*8975f5c5SAndroid Build Coastguard Worker 
117*8975f5c5SAndroid Build Coastguard Worker     // For validateStructUsage:
118*8975f5c5SAndroid Build Coastguard Worker     std::vector<std::map<Name, const TFieldListCollection *>> mStructsAndBlocksByName;
119*8975f5c5SAndroid Build Coastguard Worker     std::set<const TFunction *> mStructUsageProcessedFunctions;
120*8975f5c5SAndroid Build Coastguard Worker     bool mStructUsageFailed = false;
121*8975f5c5SAndroid Build Coastguard Worker 
122*8975f5c5SAndroid Build Coastguard Worker     // For validateExpressionTypes:
123*8975f5c5SAndroid Build Coastguard Worker     bool mExpressionTypesFailed = false;
124*8975f5c5SAndroid Build Coastguard Worker 
125*8975f5c5SAndroid Build Coastguard Worker     // For validateMultiDeclarations:
126*8975f5c5SAndroid Build Coastguard Worker     bool mMultiDeclarationsFailed = false;
127*8975f5c5SAndroid Build Coastguard Worker 
128*8975f5c5SAndroid Build Coastguard Worker     // For validateNoSwizzleOfSwizzle:
129*8975f5c5SAndroid Build Coastguard Worker     bool mNoSwizzleOfSwizzleFailed = false;
130*8975f5c5SAndroid Build Coastguard Worker 
131*8975f5c5SAndroid Build Coastguard Worker     // For validateNoQualifiersOnConstructors:
132*8975f5c5SAndroid Build Coastguard Worker     bool mNoQualifiersOnConstructorsFailed = false;
133*8975f5c5SAndroid Build Coastguard Worker 
134*8975f5c5SAndroid Build Coastguard Worker     // For validateNoStatementsAfterBranch:
135*8975f5c5SAndroid Build Coastguard Worker     bool mIsBranchVisitedInBlock        = false;
136*8975f5c5SAndroid Build Coastguard Worker     bool mNoStatementsAfterBranchFailed = false;
137*8975f5c5SAndroid Build Coastguard Worker 
138*8975f5c5SAndroid Build Coastguard Worker     bool mVariableNamingFailed = false;
139*8975f5c5SAndroid Build Coastguard Worker };
140*8975f5c5SAndroid Build Coastguard Worker 
IsSameType(const TType & a,const TType & b)141*8975f5c5SAndroid Build Coastguard Worker bool IsSameType(const TType &a, const TType &b)
142*8975f5c5SAndroid Build Coastguard Worker {
143*8975f5c5SAndroid Build Coastguard Worker     return a.getBasicType() == b.getBasicType() && a.getNominalSize() == b.getNominalSize() &&
144*8975f5c5SAndroid Build Coastguard Worker            a.getSecondarySize() == b.getSecondarySize() && a.getArraySizes() == b.getArraySizes() &&
145*8975f5c5SAndroid Build Coastguard Worker            a.getStruct() == b.getStruct() &&
146*8975f5c5SAndroid Build Coastguard Worker            (!a.isInterfaceBlock() || a.getInterfaceBlock() == b.getInterfaceBlock());
147*8975f5c5SAndroid Build Coastguard Worker }
148*8975f5c5SAndroid Build Coastguard Worker 
IsUnaryOp(TOperator op)149*8975f5c5SAndroid Build Coastguard Worker bool IsUnaryOp(TOperator op)
150*8975f5c5SAndroid Build Coastguard Worker {
151*8975f5c5SAndroid Build Coastguard Worker     switch (op)
152*8975f5c5SAndroid Build Coastguard Worker     {
153*8975f5c5SAndroid Build Coastguard Worker         case EOpNegative:
154*8975f5c5SAndroid Build Coastguard Worker         case EOpPositive:
155*8975f5c5SAndroid Build Coastguard Worker         case EOpLogicalNot:
156*8975f5c5SAndroid Build Coastguard Worker         case EOpBitwiseNot:
157*8975f5c5SAndroid Build Coastguard Worker         case EOpPostIncrement:
158*8975f5c5SAndroid Build Coastguard Worker         case EOpPostDecrement:
159*8975f5c5SAndroid Build Coastguard Worker         case EOpPreIncrement:
160*8975f5c5SAndroid Build Coastguard Worker         case EOpPreDecrement:
161*8975f5c5SAndroid Build Coastguard Worker         case EOpArrayLength:
162*8975f5c5SAndroid Build Coastguard Worker             return true;
163*8975f5c5SAndroid Build Coastguard Worker         default:
164*8975f5c5SAndroid Build Coastguard Worker             return false;
165*8975f5c5SAndroid Build Coastguard Worker     }
166*8975f5c5SAndroid Build Coastguard Worker }
167*8975f5c5SAndroid Build Coastguard Worker 
IsBinaryOp(TOperator op)168*8975f5c5SAndroid Build Coastguard Worker bool IsBinaryOp(TOperator op)
169*8975f5c5SAndroid Build Coastguard Worker {
170*8975f5c5SAndroid Build Coastguard Worker     switch (op)
171*8975f5c5SAndroid Build Coastguard Worker     {
172*8975f5c5SAndroid Build Coastguard Worker         case EOpAdd:
173*8975f5c5SAndroid Build Coastguard Worker         case EOpSub:
174*8975f5c5SAndroid Build Coastguard Worker         case EOpMul:
175*8975f5c5SAndroid Build Coastguard Worker         case EOpDiv:
176*8975f5c5SAndroid Build Coastguard Worker         case EOpIMod:
177*8975f5c5SAndroid Build Coastguard Worker         case EOpEqual:
178*8975f5c5SAndroid Build Coastguard Worker         case EOpNotEqual:
179*8975f5c5SAndroid Build Coastguard Worker         case EOpLessThan:
180*8975f5c5SAndroid Build Coastguard Worker         case EOpGreaterThan:
181*8975f5c5SAndroid Build Coastguard Worker         case EOpLessThanEqual:
182*8975f5c5SAndroid Build Coastguard Worker         case EOpGreaterThanEqual:
183*8975f5c5SAndroid Build Coastguard Worker         case EOpComma:
184*8975f5c5SAndroid Build Coastguard Worker         case EOpVectorTimesScalar:
185*8975f5c5SAndroid Build Coastguard Worker         case EOpVectorTimesMatrix:
186*8975f5c5SAndroid Build Coastguard Worker         case EOpMatrixTimesVector:
187*8975f5c5SAndroid Build Coastguard Worker         case EOpMatrixTimesScalar:
188*8975f5c5SAndroid Build Coastguard Worker         case EOpMatrixTimesMatrix:
189*8975f5c5SAndroid Build Coastguard Worker         case EOpLogicalOr:
190*8975f5c5SAndroid Build Coastguard Worker         case EOpLogicalXor:
191*8975f5c5SAndroid Build Coastguard Worker         case EOpLogicalAnd:
192*8975f5c5SAndroid Build Coastguard Worker         case EOpBitShiftLeft:
193*8975f5c5SAndroid Build Coastguard Worker         case EOpBitShiftRight:
194*8975f5c5SAndroid Build Coastguard Worker         case EOpBitwiseAnd:
195*8975f5c5SAndroid Build Coastguard Worker         case EOpBitwiseXor:
196*8975f5c5SAndroid Build Coastguard Worker         case EOpBitwiseOr:
197*8975f5c5SAndroid Build Coastguard Worker         case EOpIndexDirect:
198*8975f5c5SAndroid Build Coastguard Worker         case EOpIndexIndirect:
199*8975f5c5SAndroid Build Coastguard Worker         case EOpIndexDirectStruct:
200*8975f5c5SAndroid Build Coastguard Worker         case EOpIndexDirectInterfaceBlock:
201*8975f5c5SAndroid Build Coastguard Worker         case EOpAssign:
202*8975f5c5SAndroid Build Coastguard Worker         case EOpInitialize:
203*8975f5c5SAndroid Build Coastguard Worker         case EOpAddAssign:
204*8975f5c5SAndroid Build Coastguard Worker         case EOpSubAssign:
205*8975f5c5SAndroid Build Coastguard Worker         case EOpMulAssign:
206*8975f5c5SAndroid Build Coastguard Worker         case EOpVectorTimesMatrixAssign:
207*8975f5c5SAndroid Build Coastguard Worker         case EOpVectorTimesScalarAssign:
208*8975f5c5SAndroid Build Coastguard Worker         case EOpMatrixTimesScalarAssign:
209*8975f5c5SAndroid Build Coastguard Worker         case EOpMatrixTimesMatrixAssign:
210*8975f5c5SAndroid Build Coastguard Worker         case EOpDivAssign:
211*8975f5c5SAndroid Build Coastguard Worker         case EOpIModAssign:
212*8975f5c5SAndroid Build Coastguard Worker         case EOpBitShiftLeftAssign:
213*8975f5c5SAndroid Build Coastguard Worker         case EOpBitShiftRightAssign:
214*8975f5c5SAndroid Build Coastguard Worker         case EOpBitwiseAndAssign:
215*8975f5c5SAndroid Build Coastguard Worker         case EOpBitwiseXorAssign:
216*8975f5c5SAndroid Build Coastguard Worker         case EOpBitwiseOrAssign:
217*8975f5c5SAndroid Build Coastguard Worker             return true;
218*8975f5c5SAndroid Build Coastguard Worker         default:
219*8975f5c5SAndroid Build Coastguard Worker             return false;
220*8975f5c5SAndroid Build Coastguard Worker     }
221*8975f5c5SAndroid Build Coastguard Worker }
222*8975f5c5SAndroid Build Coastguard Worker 
IsBranchOp(TOperator op)223*8975f5c5SAndroid Build Coastguard Worker bool IsBranchOp(TOperator op)
224*8975f5c5SAndroid Build Coastguard Worker {
225*8975f5c5SAndroid Build Coastguard Worker     switch (op)
226*8975f5c5SAndroid Build Coastguard Worker     {
227*8975f5c5SAndroid Build Coastguard Worker         case EOpKill:
228*8975f5c5SAndroid Build Coastguard Worker         case EOpReturn:
229*8975f5c5SAndroid Build Coastguard Worker         case EOpBreak:
230*8975f5c5SAndroid Build Coastguard Worker         case EOpContinue:
231*8975f5c5SAndroid Build Coastguard Worker             return true;
232*8975f5c5SAndroid Build Coastguard Worker         default:
233*8975f5c5SAndroid Build Coastguard Worker             return false;
234*8975f5c5SAndroid Build Coastguard Worker     }
235*8975f5c5SAndroid Build Coastguard Worker }
236*8975f5c5SAndroid Build Coastguard Worker 
validate(TIntermNode * root,TDiagnostics * diagnostics,const ValidateASTOptions & options)237*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::validate(TIntermNode *root,
238*8975f5c5SAndroid Build Coastguard Worker                            TDiagnostics *diagnostics,
239*8975f5c5SAndroid Build Coastguard Worker                            const ValidateASTOptions &options)
240*8975f5c5SAndroid Build Coastguard Worker {
241*8975f5c5SAndroid Build Coastguard Worker     ValidateAST validate(root, diagnostics, options);
242*8975f5c5SAndroid Build Coastguard Worker     root->traverse(&validate);
243*8975f5c5SAndroid Build Coastguard Worker     return validate.validateInternal();
244*8975f5c5SAndroid Build Coastguard Worker }
245*8975f5c5SAndroid Build Coastguard Worker 
ValidateAST(TIntermNode * root,TDiagnostics * diagnostics,const ValidateASTOptions & options)246*8975f5c5SAndroid Build Coastguard Worker ValidateAST::ValidateAST(TIntermNode *root,
247*8975f5c5SAndroid Build Coastguard Worker                          TDiagnostics *diagnostics,
248*8975f5c5SAndroid Build Coastguard Worker                          const ValidateASTOptions &options)
249*8975f5c5SAndroid Build Coastguard Worker     : TIntermTraverser(true, false, true, nullptr), mOptions(options), mDiagnostics(diagnostics)
250*8975f5c5SAndroid Build Coastguard Worker {
251*8975f5c5SAndroid Build Coastguard Worker     bool isTreeRoot = root->getAsBlock() && root->getAsBlock()->isTreeRoot();
252*8975f5c5SAndroid Build Coastguard Worker 
253*8975f5c5SAndroid Build Coastguard Worker     // Some validations are not applicable unless run on the entire tree.
254*8975f5c5SAndroid Build Coastguard Worker     if (!isTreeRoot)
255*8975f5c5SAndroid Build Coastguard Worker     {
256*8975f5c5SAndroid Build Coastguard Worker         mOptions.validateVariableReferences = false;
257*8975f5c5SAndroid Build Coastguard Worker         mOptions.validateFunctionCall       = false;
258*8975f5c5SAndroid Build Coastguard Worker         mOptions.validateStructUsage        = false;
259*8975f5c5SAndroid Build Coastguard Worker     }
260*8975f5c5SAndroid Build Coastguard Worker 
261*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validateSingleParent)
262*8975f5c5SAndroid Build Coastguard Worker     {
263*8975f5c5SAndroid Build Coastguard Worker         mParent[root] = nullptr;
264*8975f5c5SAndroid Build Coastguard Worker     }
265*8975f5c5SAndroid Build Coastguard Worker }
266*8975f5c5SAndroid Build Coastguard Worker 
visitNode(Visit visit,TIntermNode * node)267*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::visitNode(Visit visit, TIntermNode *node)
268*8975f5c5SAndroid Build Coastguard Worker {
269*8975f5c5SAndroid Build Coastguard Worker     if (visit == PreVisit && mOptions.validateSingleParent)
270*8975f5c5SAndroid Build Coastguard Worker     {
271*8975f5c5SAndroid Build Coastguard Worker         size_t childCount = node->getChildCount();
272*8975f5c5SAndroid Build Coastguard Worker         for (size_t i = 0; i < childCount; ++i)
273*8975f5c5SAndroid Build Coastguard Worker         {
274*8975f5c5SAndroid Build Coastguard Worker             TIntermNode *child = node->getChildNode(i);
275*8975f5c5SAndroid Build Coastguard Worker             if (mParent.find(child) != mParent.end())
276*8975f5c5SAndroid Build Coastguard Worker             {
277*8975f5c5SAndroid Build Coastguard Worker                 // If child is visited twice but through the same parent, the problem is in one of
278*8975f5c5SAndroid Build Coastguard Worker                 // the ancestors.
279*8975f5c5SAndroid Build Coastguard Worker                 if (mParent[child] != node)
280*8975f5c5SAndroid Build Coastguard Worker                 {
281*8975f5c5SAndroid Build Coastguard Worker                     mDiagnostics->error(node->getLine(), "Found child with two parents",
282*8975f5c5SAndroid Build Coastguard Worker                                         "<validateSingleParent>");
283*8975f5c5SAndroid Build Coastguard Worker                     mSingleParentFailed = true;
284*8975f5c5SAndroid Build Coastguard Worker                 }
285*8975f5c5SAndroid Build Coastguard Worker             }
286*8975f5c5SAndroid Build Coastguard Worker 
287*8975f5c5SAndroid Build Coastguard Worker             mParent[child] = node;
288*8975f5c5SAndroid Build Coastguard Worker         }
289*8975f5c5SAndroid Build Coastguard Worker     }
290*8975f5c5SAndroid Build Coastguard Worker 
291*8975f5c5SAndroid Build Coastguard Worker     if (visit == PreVisit && mOptions.validateNoStatementsAfterBranch)
292*8975f5c5SAndroid Build Coastguard Worker     {
293*8975f5c5SAndroid Build Coastguard Worker         // If a branch has already been visited in this block, there should be no statements that
294*8975f5c5SAndroid Build Coastguard Worker         // follow.  Only expected node visit should be PostVisit of the block.
295*8975f5c5SAndroid Build Coastguard Worker         if (mIsBranchVisitedInBlock)
296*8975f5c5SAndroid Build Coastguard Worker         {
297*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(node->getLine(), "Found dead code after branch",
298*8975f5c5SAndroid Build Coastguard Worker                                 "<validateNoStatementsAfterBranch>");
299*8975f5c5SAndroid Build Coastguard Worker             mNoStatementsAfterBranchFailed = true;
300*8975f5c5SAndroid Build Coastguard Worker         }
301*8975f5c5SAndroid Build Coastguard Worker     }
302*8975f5c5SAndroid Build Coastguard Worker }
303*8975f5c5SAndroid Build Coastguard Worker 
visitStructOrInterfaceBlockDeclaration(const TType & type,const TSourceLoc & location)304*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::visitStructOrInterfaceBlockDeclaration(const TType &type,
305*8975f5c5SAndroid Build Coastguard Worker                                                          const TSourceLoc &location)
306*8975f5c5SAndroid Build Coastguard Worker {
307*8975f5c5SAndroid Build Coastguard Worker     if (type.getStruct() == nullptr && type.getInterfaceBlock() == nullptr)
308*8975f5c5SAndroid Build Coastguard Worker     {
309*8975f5c5SAndroid Build Coastguard Worker         return;
310*8975f5c5SAndroid Build Coastguard Worker     }
311*8975f5c5SAndroid Build Coastguard Worker 
312*8975f5c5SAndroid Build Coastguard Worker     // Make sure the structure or interface block is not doubly defined.
313*8975f5c5SAndroid Build Coastguard Worker     Name typeName;
314*8975f5c5SAndroid Build Coastguard Worker     const TFieldListCollection *namedStructOrBlock = getStructOrInterfaceBlock(type, &typeName);
315*8975f5c5SAndroid Build Coastguard Worker 
316*8975f5c5SAndroid Build Coastguard Worker     // Recurse the fields of the structure or interface block and check members of structure type.
317*8975f5c5SAndroid Build Coastguard Worker     // This is done before visiting the struct itself, because if the fields refer to a struct with
318*8975f5c5SAndroid Build Coastguard Worker     // the same name, they would be referencing the struct declared in an outer scope.
319*8975f5c5SAndroid Build Coastguard Worker     {
320*8975f5c5SAndroid Build Coastguard Worker         // Note that structOrBlock was previously only set for named structures, so make sure
321*8975f5c5SAndroid Build Coastguard Worker         // nameless structs are also recursed.
322*8975f5c5SAndroid Build Coastguard Worker         const TFieldListCollection *structOrBlock = namedStructOrBlock;
323*8975f5c5SAndroid Build Coastguard Worker         if (structOrBlock == nullptr)
324*8975f5c5SAndroid Build Coastguard Worker         {
325*8975f5c5SAndroid Build Coastguard Worker             structOrBlock = type.getStruct();
326*8975f5c5SAndroid Build Coastguard Worker         }
327*8975f5c5SAndroid Build Coastguard Worker         ASSERT(structOrBlock != nullptr);
328*8975f5c5SAndroid Build Coastguard Worker 
329*8975f5c5SAndroid Build Coastguard Worker         for (const TField *field : structOrBlock->fields())
330*8975f5c5SAndroid Build Coastguard Worker         {
331*8975f5c5SAndroid Build Coastguard Worker             visitStructUsage(*field->type(), field->line());
332*8975f5c5SAndroid Build Coastguard Worker         }
333*8975f5c5SAndroid Build Coastguard Worker     }
334*8975f5c5SAndroid Build Coastguard Worker 
335*8975f5c5SAndroid Build Coastguard Worker     if (namedStructOrBlock)
336*8975f5c5SAndroid Build Coastguard Worker     {
337*8975f5c5SAndroid Build Coastguard Worker         ASSERT(!typeName.empty());
338*8975f5c5SAndroid Build Coastguard Worker         // Structures are not allowed to be doubly defined
339*8975f5c5SAndroid Build Coastguard Worker         if (type.getStruct() == nullptr)
340*8975f5c5SAndroid Build Coastguard Worker         {
341*8975f5c5SAndroid Build Coastguard Worker             // Allow interfaces to be doubly-defined.
342*8975f5c5SAndroid Build Coastguard Worker             ImmutableString rawName = typeName.rawName();
343*8975f5c5SAndroid Build Coastguard Worker 
344*8975f5c5SAndroid Build Coastguard Worker             if (IsShaderIn(type.getQualifier()))
345*8975f5c5SAndroid Build Coastguard Worker             {
346*8975f5c5SAndroid Build Coastguard Worker                 rawName = BuildConcatenatedImmutableString(rawName, "<input>");
347*8975f5c5SAndroid Build Coastguard Worker             }
348*8975f5c5SAndroid Build Coastguard Worker             else if (IsShaderOut(type.getQualifier()))
349*8975f5c5SAndroid Build Coastguard Worker             {
350*8975f5c5SAndroid Build Coastguard Worker                 rawName = BuildConcatenatedImmutableString(rawName, "<output>");
351*8975f5c5SAndroid Build Coastguard Worker             }
352*8975f5c5SAndroid Build Coastguard Worker             else if (IsStorageBuffer(type.getQualifier()))
353*8975f5c5SAndroid Build Coastguard Worker             {
354*8975f5c5SAndroid Build Coastguard Worker                 rawName = BuildConcatenatedImmutableString(rawName, "<buffer>");
355*8975f5c5SAndroid Build Coastguard Worker             }
356*8975f5c5SAndroid Build Coastguard Worker             else if (type.getQualifier() == EvqUniform)
357*8975f5c5SAndroid Build Coastguard Worker             {
358*8975f5c5SAndroid Build Coastguard Worker                 rawName = BuildConcatenatedImmutableString(rawName, "<uniform>");
359*8975f5c5SAndroid Build Coastguard Worker             }
360*8975f5c5SAndroid Build Coastguard Worker             typeName = Name(rawName, typeName.symbolType());
361*8975f5c5SAndroid Build Coastguard Worker         }
362*8975f5c5SAndroid Build Coastguard Worker 
363*8975f5c5SAndroid Build Coastguard Worker         if (mStructsAndBlocksByName.back().find(typeName) != mStructsAndBlocksByName.back().end())
364*8975f5c5SAndroid Build Coastguard Worker         {
365*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(location,
366*8975f5c5SAndroid Build Coastguard Worker                                 "Found redeclaration of struct or interface block with the same "
367*8975f5c5SAndroid Build Coastguard Worker                                 "name in the same scope <validateStructUsage>",
368*8975f5c5SAndroid Build Coastguard Worker                                 typeName.rawName().data());
369*8975f5c5SAndroid Build Coastguard Worker             mStructUsageFailed = true;
370*8975f5c5SAndroid Build Coastguard Worker         }
371*8975f5c5SAndroid Build Coastguard Worker         else
372*8975f5c5SAndroid Build Coastguard Worker         {
373*8975f5c5SAndroid Build Coastguard Worker             // First encounter.
374*8975f5c5SAndroid Build Coastguard Worker             mStructsAndBlocksByName.back()[typeName] = namedStructOrBlock;
375*8975f5c5SAndroid Build Coastguard Worker         }
376*8975f5c5SAndroid Build Coastguard Worker     }
377*8975f5c5SAndroid Build Coastguard Worker }
378*8975f5c5SAndroid Build Coastguard Worker 
visitStructUsage(const TType & type,const TSourceLoc & location)379*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::visitStructUsage(const TType &type, const TSourceLoc &location)
380*8975f5c5SAndroid Build Coastguard Worker {
381*8975f5c5SAndroid Build Coastguard Worker     if (type.getStruct() == nullptr)
382*8975f5c5SAndroid Build Coastguard Worker     {
383*8975f5c5SAndroid Build Coastguard Worker         return;
384*8975f5c5SAndroid Build Coastguard Worker     }
385*8975f5c5SAndroid Build Coastguard Worker 
386*8975f5c5SAndroid Build Coastguard Worker     // Make sure the structure being referenced has the same pointer as the closest (in scope)
387*8975f5c5SAndroid Build Coastguard Worker     // definition.
388*8975f5c5SAndroid Build Coastguard Worker     const TStructure *structure     = type.getStruct();
389*8975f5c5SAndroid Build Coastguard Worker     const Name typeName(*structure);
390*8975f5c5SAndroid Build Coastguard Worker 
391*8975f5c5SAndroid Build Coastguard Worker     bool foundDeclaration = false;
392*8975f5c5SAndroid Build Coastguard Worker     for (size_t scopeIndex = mStructsAndBlocksByName.size(); scopeIndex > 0; --scopeIndex)
393*8975f5c5SAndroid Build Coastguard Worker     {
394*8975f5c5SAndroid Build Coastguard Worker         const std::map<Name, const TFieldListCollection *> &scopeDecls =
395*8975f5c5SAndroid Build Coastguard Worker             mStructsAndBlocksByName[scopeIndex - 1];
396*8975f5c5SAndroid Build Coastguard Worker 
397*8975f5c5SAndroid Build Coastguard Worker         auto iter = scopeDecls.find(typeName);
398*8975f5c5SAndroid Build Coastguard Worker         if (iter != scopeDecls.end())
399*8975f5c5SAndroid Build Coastguard Worker         {
400*8975f5c5SAndroid Build Coastguard Worker             foundDeclaration = true;
401*8975f5c5SAndroid Build Coastguard Worker 
402*8975f5c5SAndroid Build Coastguard Worker             if (iter->second != structure)
403*8975f5c5SAndroid Build Coastguard Worker             {
404*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->error(location,
405*8975f5c5SAndroid Build Coastguard Worker                                     "Found reference to struct or interface block with doubly "
406*8975f5c5SAndroid Build Coastguard Worker                                     "created type <validateStructUsage>",
407*8975f5c5SAndroid Build Coastguard Worker                                     typeName.rawName().data());
408*8975f5c5SAndroid Build Coastguard Worker                 mStructUsageFailed = true;
409*8975f5c5SAndroid Build Coastguard Worker             }
410*8975f5c5SAndroid Build Coastguard Worker 
411*8975f5c5SAndroid Build Coastguard Worker             break;
412*8975f5c5SAndroid Build Coastguard Worker         }
413*8975f5c5SAndroid Build Coastguard Worker     }
414*8975f5c5SAndroid Build Coastguard Worker 
415*8975f5c5SAndroid Build Coastguard Worker     if (!foundDeclaration)
416*8975f5c5SAndroid Build Coastguard Worker     {
417*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->error(location,
418*8975f5c5SAndroid Build Coastguard Worker                             "Found reference to struct or interface block with no declaration "
419*8975f5c5SAndroid Build Coastguard Worker                             "<validateStructUsage>",
420*8975f5c5SAndroid Build Coastguard Worker                             typeName.rawName().data());
421*8975f5c5SAndroid Build Coastguard Worker         mStructUsageFailed = true;
422*8975f5c5SAndroid Build Coastguard Worker     }
423*8975f5c5SAndroid Build Coastguard Worker }
424*8975f5c5SAndroid Build Coastguard Worker 
visitBuiltInFunction(TIntermOperator * node,const TFunction * function)425*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::visitBuiltInFunction(TIntermOperator *node, const TFunction *function)
426*8975f5c5SAndroid Build Coastguard Worker {
427*8975f5c5SAndroid Build Coastguard Worker     const TOperator op = node->getOp();
428*8975f5c5SAndroid Build Coastguard Worker     if (!BuiltInGroup::IsBuiltIn(op))
429*8975f5c5SAndroid Build Coastguard Worker     {
430*8975f5c5SAndroid Build Coastguard Worker         return;
431*8975f5c5SAndroid Build Coastguard Worker     }
432*8975f5c5SAndroid Build Coastguard Worker 
433*8975f5c5SAndroid Build Coastguard Worker     ImmutableString opValue = BuildConcatenatedImmutableString("op: ", op);
434*8975f5c5SAndroid Build Coastguard Worker     if (function == nullptr)
435*8975f5c5SAndroid Build Coastguard Worker     {
436*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->error(node->getLine(),
437*8975f5c5SAndroid Build Coastguard Worker                             "Found node calling built-in without a reference to the built-in "
438*8975f5c5SAndroid Build Coastguard Worker                             "function <validateBuiltInOps>",
439*8975f5c5SAndroid Build Coastguard Worker                             opValue.data());
440*8975f5c5SAndroid Build Coastguard Worker         mVariableReferencesFailed = true;
441*8975f5c5SAndroid Build Coastguard Worker     }
442*8975f5c5SAndroid Build Coastguard Worker     else if (function->getBuiltInOp() != op)
443*8975f5c5SAndroid Build Coastguard Worker     {
444*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->error(node->getLine(),
445*8975f5c5SAndroid Build Coastguard Worker                             "Found node calling built-in with a reference to a different function "
446*8975f5c5SAndroid Build Coastguard Worker                             "<validateBuiltInOps>",
447*8975f5c5SAndroid Build Coastguard Worker                             opValue.data());
448*8975f5c5SAndroid Build Coastguard Worker         mVariableReferencesFailed = true;
449*8975f5c5SAndroid Build Coastguard Worker     }
450*8975f5c5SAndroid Build Coastguard Worker }
451*8975f5c5SAndroid Build Coastguard Worker 
visitFunctionCall(TIntermAggregate * node)452*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::visitFunctionCall(TIntermAggregate *node)
453*8975f5c5SAndroid Build Coastguard Worker {
454*8975f5c5SAndroid Build Coastguard Worker     if (node->getOp() != EOpCallFunctionInAST)
455*8975f5c5SAndroid Build Coastguard Worker     {
456*8975f5c5SAndroid Build Coastguard Worker         return;
457*8975f5c5SAndroid Build Coastguard Worker     }
458*8975f5c5SAndroid Build Coastguard Worker 
459*8975f5c5SAndroid Build Coastguard Worker     const TFunction *function = node->getFunction();
460*8975f5c5SAndroid Build Coastguard Worker 
461*8975f5c5SAndroid Build Coastguard Worker     if (function == nullptr)
462*8975f5c5SAndroid Build Coastguard Worker     {
463*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->error(node->getLine(),
464*8975f5c5SAndroid Build Coastguard Worker                             "Found node calling function without a reference to it",
465*8975f5c5SAndroid Build Coastguard Worker                             "<validateFunctionCall>");
466*8975f5c5SAndroid Build Coastguard Worker         mFunctionCallFailed = true;
467*8975f5c5SAndroid Build Coastguard Worker     }
468*8975f5c5SAndroid Build Coastguard Worker     else if (mDeclaredFunctions.find(function) == mDeclaredFunctions.end())
469*8975f5c5SAndroid Build Coastguard Worker     {
470*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->error(node->getLine(),
471*8975f5c5SAndroid Build Coastguard Worker                             "Found node calling previously undeclared function "
472*8975f5c5SAndroid Build Coastguard Worker                             "<validateFunctionCall>",
473*8975f5c5SAndroid Build Coastguard Worker                             function->name().data());
474*8975f5c5SAndroid Build Coastguard Worker         mFunctionCallFailed = true;
475*8975f5c5SAndroid Build Coastguard Worker     }
476*8975f5c5SAndroid Build Coastguard Worker }
477*8975f5c5SAndroid Build Coastguard Worker 
validateExpressionTypeBinary(TIntermBinary * node)478*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::validateExpressionTypeBinary(TIntermBinary *node)
479*8975f5c5SAndroid Build Coastguard Worker {
480*8975f5c5SAndroid Build Coastguard Worker     switch (node->getOp())
481*8975f5c5SAndroid Build Coastguard Worker     {
482*8975f5c5SAndroid Build Coastguard Worker         case EOpIndexDirect:
483*8975f5c5SAndroid Build Coastguard Worker         case EOpIndexIndirect:
484*8975f5c5SAndroid Build Coastguard Worker         {
485*8975f5c5SAndroid Build Coastguard Worker             TType expectedType(node->getLeft()->getType());
486*8975f5c5SAndroid Build Coastguard Worker             if (!expectedType.isArray())
487*8975f5c5SAndroid Build Coastguard Worker             {
488*8975f5c5SAndroid Build Coastguard Worker                 // TODO: Validate matrix column selection and vector component selection.
489*8975f5c5SAndroid Build Coastguard Worker                 // http://anglebug.com/42261441
490*8975f5c5SAndroid Build Coastguard Worker                 break;
491*8975f5c5SAndroid Build Coastguard Worker             }
492*8975f5c5SAndroid Build Coastguard Worker 
493*8975f5c5SAndroid Build Coastguard Worker             expectedType.toArrayElementType();
494*8975f5c5SAndroid Build Coastguard Worker 
495*8975f5c5SAndroid Build Coastguard Worker             if (!IsSameType(node->getType(), expectedType))
496*8975f5c5SAndroid Build Coastguard Worker             {
497*8975f5c5SAndroid Build Coastguard Worker                 const TSymbol *symbol = expectedType.getStruct();
498*8975f5c5SAndroid Build Coastguard Worker                 if (symbol == nullptr)
499*8975f5c5SAndroid Build Coastguard Worker                 {
500*8975f5c5SAndroid Build Coastguard Worker                     symbol = expectedType.getInterfaceBlock();
501*8975f5c5SAndroid Build Coastguard Worker                 }
502*8975f5c5SAndroid Build Coastguard Worker                 const char *name = nullptr;
503*8975f5c5SAndroid Build Coastguard Worker                 if (symbol)
504*8975f5c5SAndroid Build Coastguard Worker                 {
505*8975f5c5SAndroid Build Coastguard Worker                     name = symbol->name().data();
506*8975f5c5SAndroid Build Coastguard Worker                 }
507*8975f5c5SAndroid Build Coastguard Worker                 else if (expectedType.isScalar())
508*8975f5c5SAndroid Build Coastguard Worker                 {
509*8975f5c5SAndroid Build Coastguard Worker                     name = "<scalar array>";
510*8975f5c5SAndroid Build Coastguard Worker                 }
511*8975f5c5SAndroid Build Coastguard Worker                 else if (expectedType.isVector())
512*8975f5c5SAndroid Build Coastguard Worker                 {
513*8975f5c5SAndroid Build Coastguard Worker                     name = "<vector array>";
514*8975f5c5SAndroid Build Coastguard Worker                 }
515*8975f5c5SAndroid Build Coastguard Worker                 else
516*8975f5c5SAndroid Build Coastguard Worker                 {
517*8975f5c5SAndroid Build Coastguard Worker                     ASSERT(expectedType.isMatrix());
518*8975f5c5SAndroid Build Coastguard Worker                     name = "<matrix array>";
519*8975f5c5SAndroid Build Coastguard Worker                 }
520*8975f5c5SAndroid Build Coastguard Worker 
521*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->error(
522*8975f5c5SAndroid Build Coastguard Worker                     node->getLine(),
523*8975f5c5SAndroid Build Coastguard Worker                     "Found index node with type that is inconsistent with the array being indexed "
524*8975f5c5SAndroid Build Coastguard Worker                     "<validateExpressionTypes>",
525*8975f5c5SAndroid Build Coastguard Worker                     name);
526*8975f5c5SAndroid Build Coastguard Worker                 mExpressionTypesFailed = true;
527*8975f5c5SAndroid Build Coastguard Worker             }
528*8975f5c5SAndroid Build Coastguard Worker         }
529*8975f5c5SAndroid Build Coastguard Worker         break;
530*8975f5c5SAndroid Build Coastguard Worker         default:
531*8975f5c5SAndroid Build Coastguard Worker             // TODO: Validate other expressions. http://anglebug.com/42261441
532*8975f5c5SAndroid Build Coastguard Worker             break;
533*8975f5c5SAndroid Build Coastguard Worker     }
534*8975f5c5SAndroid Build Coastguard Worker 
535*8975f5c5SAndroid Build Coastguard Worker     switch (node->getOp())
536*8975f5c5SAndroid Build Coastguard Worker     {
537*8975f5c5SAndroid Build Coastguard Worker         case EOpIndexDirect:
538*8975f5c5SAndroid Build Coastguard Worker         case EOpIndexDirectStruct:
539*8975f5c5SAndroid Build Coastguard Worker         case EOpIndexDirectInterfaceBlock:
540*8975f5c5SAndroid Build Coastguard Worker             if (node->getRight()->getAsConstantUnion() == nullptr)
541*8975f5c5SAndroid Build Coastguard Worker             {
542*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->error(node->getLine(),
543*8975f5c5SAndroid Build Coastguard Worker                                     "Found direct index node with a non-constant index",
544*8975f5c5SAndroid Build Coastguard Worker                                     "<validateExpressionTypes>");
545*8975f5c5SAndroid Build Coastguard Worker                 mExpressionTypesFailed = true;
546*8975f5c5SAndroid Build Coastguard Worker             }
547*8975f5c5SAndroid Build Coastguard Worker             break;
548*8975f5c5SAndroid Build Coastguard Worker         default:
549*8975f5c5SAndroid Build Coastguard Worker             break;
550*8975f5c5SAndroid Build Coastguard Worker     }
551*8975f5c5SAndroid Build Coastguard Worker }
552*8975f5c5SAndroid Build Coastguard Worker 
validateExpressionTypeSwitch(TIntermSwitch * node)553*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::validateExpressionTypeSwitch(TIntermSwitch *node)
554*8975f5c5SAndroid Build Coastguard Worker {
555*8975f5c5SAndroid Build Coastguard Worker     const TType &selectorType = node->getInit()->getType();
556*8975f5c5SAndroid Build Coastguard Worker 
557*8975f5c5SAndroid Build Coastguard Worker     if (selectorType.getBasicType() != EbtYuvCscStandardEXT &&
558*8975f5c5SAndroid Build Coastguard Worker         selectorType.getBasicType() != EbtInt && selectorType.getBasicType() != EbtUInt)
559*8975f5c5SAndroid Build Coastguard Worker     {
560*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->error(node->getLine(), "Found switch selector expression that is not integer",
561*8975f5c5SAndroid Build Coastguard Worker                             "<validateExpressionTypes>");
562*8975f5c5SAndroid Build Coastguard Worker         mExpressionTypesFailed = true;
563*8975f5c5SAndroid Build Coastguard Worker     }
564*8975f5c5SAndroid Build Coastguard Worker     else if (!selectorType.isScalar())
565*8975f5c5SAndroid Build Coastguard Worker     {
566*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->error(node->getLine(), "Found switch selector expression that is not scalar",
567*8975f5c5SAndroid Build Coastguard Worker                             "<validateExpressionTypes>");
568*8975f5c5SAndroid Build Coastguard Worker         mExpressionTypesFailed = true;
569*8975f5c5SAndroid Build Coastguard Worker     }
570*8975f5c5SAndroid Build Coastguard Worker }
571*8975f5c5SAndroid Build Coastguard Worker 
visitVariableNeedingDeclaration(TIntermSymbol * node)572*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::visitVariableNeedingDeclaration(TIntermSymbol *node)
573*8975f5c5SAndroid Build Coastguard Worker {
574*8975f5c5SAndroid Build Coastguard Worker     const TVariable *variable = &node->variable();
575*8975f5c5SAndroid Build Coastguard Worker     const TType &type         = node->getType();
576*8975f5c5SAndroid Build Coastguard Worker 
577*8975f5c5SAndroid Build Coastguard Worker     // If it's a reference to a field of a nameless interface block, match it by index and name.
578*8975f5c5SAndroid Build Coastguard Worker     if (type.getInterfaceBlock() && !type.isInterfaceBlock())
579*8975f5c5SAndroid Build Coastguard Worker     {
580*8975f5c5SAndroid Build Coastguard Worker         const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
581*8975f5c5SAndroid Build Coastguard Worker         const TFieldList &fieldList           = interfaceBlock->fields();
582*8975f5c5SAndroid Build Coastguard Worker         const size_t fieldIndex               = type.getInterfaceBlockFieldIndex();
583*8975f5c5SAndroid Build Coastguard Worker 
584*8975f5c5SAndroid Build Coastguard Worker         if (mNamelessInterfaceBlocks.count(interfaceBlock) == 0)
585*8975f5c5SAndroid Build Coastguard Worker         {
586*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(node->getLine(),
587*8975f5c5SAndroid Build Coastguard Worker                                 "Found reference to undeclared or inconsistenly transformed "
588*8975f5c5SAndroid Build Coastguard Worker                                 "nameless interface block <validateVariableReferences>",
589*8975f5c5SAndroid Build Coastguard Worker                                 node->getName().data());
590*8975f5c5SAndroid Build Coastguard Worker             mVariableReferencesFailed = true;
591*8975f5c5SAndroid Build Coastguard Worker         }
592*8975f5c5SAndroid Build Coastguard Worker         else if (fieldIndex >= fieldList.size() || node->getName() != fieldList[fieldIndex]->name())
593*8975f5c5SAndroid Build Coastguard Worker         {
594*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(node->getLine(),
595*8975f5c5SAndroid Build Coastguard Worker                                 "Found reference to inconsistenly transformed nameless "
596*8975f5c5SAndroid Build Coastguard Worker                                 "interface block field <validateVariableReferences>",
597*8975f5c5SAndroid Build Coastguard Worker                                 node->getName().data());
598*8975f5c5SAndroid Build Coastguard Worker             mVariableReferencesFailed = true;
599*8975f5c5SAndroid Build Coastguard Worker         }
600*8975f5c5SAndroid Build Coastguard Worker         return;
601*8975f5c5SAndroid Build Coastguard Worker     }
602*8975f5c5SAndroid Build Coastguard Worker 
603*8975f5c5SAndroid Build Coastguard Worker     const bool isStructDeclaration =
604*8975f5c5SAndroid Build Coastguard Worker         type.isStructSpecifier() && variable->symbolType() == SymbolType::Empty;
605*8975f5c5SAndroid Build Coastguard Worker 
606*8975f5c5SAndroid Build Coastguard Worker     if (!isStructDeclaration && !isVariableDeclared(variable))
607*8975f5c5SAndroid Build Coastguard Worker     {
608*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->error(node->getLine(),
609*8975f5c5SAndroid Build Coastguard Worker                             "Found reference to undeclared or inconsistently transformed "
610*8975f5c5SAndroid Build Coastguard Worker                             "variable <validateVariableReferences>",
611*8975f5c5SAndroid Build Coastguard Worker                             node->getName().data());
612*8975f5c5SAndroid Build Coastguard Worker         mVariableReferencesFailed = true;
613*8975f5c5SAndroid Build Coastguard Worker     }
614*8975f5c5SAndroid Build Coastguard Worker }
615*8975f5c5SAndroid Build Coastguard Worker 
visitBuiltInVariable(TIntermSymbol * node)616*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::visitBuiltInVariable(TIntermSymbol *node)
617*8975f5c5SAndroid Build Coastguard Worker {
618*8975f5c5SAndroid Build Coastguard Worker     const TVariable *variable = &node->variable();
619*8975f5c5SAndroid Build Coastguard Worker     ImmutableString name      = variable->name();
620*8975f5c5SAndroid Build Coastguard Worker 
621*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validateVariableReferences)
622*8975f5c5SAndroid Build Coastguard Worker     {
623*8975f5c5SAndroid Build Coastguard Worker         auto iter = mReferencedBuiltIns.find(name);
624*8975f5c5SAndroid Build Coastguard Worker         if (iter == mReferencedBuiltIns.end())
625*8975f5c5SAndroid Build Coastguard Worker         {
626*8975f5c5SAndroid Build Coastguard Worker             mReferencedBuiltIns[name] = variable;
627*8975f5c5SAndroid Build Coastguard Worker             return;
628*8975f5c5SAndroid Build Coastguard Worker         }
629*8975f5c5SAndroid Build Coastguard Worker 
630*8975f5c5SAndroid Build Coastguard Worker         if (variable != iter->second)
631*8975f5c5SAndroid Build Coastguard Worker         {
632*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(
633*8975f5c5SAndroid Build Coastguard Worker                 node->getLine(),
634*8975f5c5SAndroid Build Coastguard Worker                 "Found inconsistent references to built-in variable <validateVariableReferences>",
635*8975f5c5SAndroid Build Coastguard Worker                 name.data());
636*8975f5c5SAndroid Build Coastguard Worker             mVariableReferencesFailed = true;
637*8975f5c5SAndroid Build Coastguard Worker         }
638*8975f5c5SAndroid Build Coastguard Worker     }
639*8975f5c5SAndroid Build Coastguard Worker 
640*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validateQualifiers)
641*8975f5c5SAndroid Build Coastguard Worker     {
642*8975f5c5SAndroid Build Coastguard Worker         TQualifier qualifier = variable->getType().getQualifier();
643*8975f5c5SAndroid Build Coastguard Worker 
644*8975f5c5SAndroid Build Coastguard Worker         if ((name == "gl_ClipDistance" && qualifier != EvqClipDistance) ||
645*8975f5c5SAndroid Build Coastguard Worker             (name == "gl_CullDistance" && qualifier != EvqCullDistance) ||
646*8975f5c5SAndroid Build Coastguard Worker             (name == "gl_FragDepth" && qualifier != EvqFragDepth) ||
647*8975f5c5SAndroid Build Coastguard Worker             (name == "gl_LastFragData" && qualifier != EvqLastFragData) ||
648*8975f5c5SAndroid Build Coastguard Worker             (name == "gl_LastFragColorARM" && qualifier != EvqLastFragColor) ||
649*8975f5c5SAndroid Build Coastguard Worker             (name == "gl_LastFragDepthARM" && qualifier != EvqLastFragDepth) ||
650*8975f5c5SAndroid Build Coastguard Worker             (name == "gl_LastFragStencilARM" && qualifier != EvqLastFragStencil))
651*8975f5c5SAndroid Build Coastguard Worker         {
652*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(
653*8975f5c5SAndroid Build Coastguard Worker                 node->getLine(),
654*8975f5c5SAndroid Build Coastguard Worker                 "Incorrect qualifier applied to redeclared built-in <validateQualifiers>",
655*8975f5c5SAndroid Build Coastguard Worker                 name.data());
656*8975f5c5SAndroid Build Coastguard Worker             mQualifiersFailed = true;
657*8975f5c5SAndroid Build Coastguard Worker         }
658*8975f5c5SAndroid Build Coastguard Worker     }
659*8975f5c5SAndroid Build Coastguard Worker }
660*8975f5c5SAndroid Build Coastguard Worker 
scope(Visit visit)661*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::scope(Visit visit)
662*8975f5c5SAndroid Build Coastguard Worker {
663*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validateVariableReferences)
664*8975f5c5SAndroid Build Coastguard Worker     {
665*8975f5c5SAndroid Build Coastguard Worker         if (visit == PreVisit)
666*8975f5c5SAndroid Build Coastguard Worker         {
667*8975f5c5SAndroid Build Coastguard Worker             mDeclaredVariables.push_back({});
668*8975f5c5SAndroid Build Coastguard Worker         }
669*8975f5c5SAndroid Build Coastguard Worker         else if (visit == PostVisit)
670*8975f5c5SAndroid Build Coastguard Worker         {
671*8975f5c5SAndroid Build Coastguard Worker             mDeclaredVariables.pop_back();
672*8975f5c5SAndroid Build Coastguard Worker         }
673*8975f5c5SAndroid Build Coastguard Worker     }
674*8975f5c5SAndroid Build Coastguard Worker 
675*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validateStructUsage)
676*8975f5c5SAndroid Build Coastguard Worker     {
677*8975f5c5SAndroid Build Coastguard Worker         if (visit == PreVisit)
678*8975f5c5SAndroid Build Coastguard Worker         {
679*8975f5c5SAndroid Build Coastguard Worker             mStructsAndBlocksByName.push_back({});
680*8975f5c5SAndroid Build Coastguard Worker         }
681*8975f5c5SAndroid Build Coastguard Worker         else if (visit == PostVisit)
682*8975f5c5SAndroid Build Coastguard Worker         {
683*8975f5c5SAndroid Build Coastguard Worker             mStructsAndBlocksByName.pop_back();
684*8975f5c5SAndroid Build Coastguard Worker         }
685*8975f5c5SAndroid Build Coastguard Worker     }
686*8975f5c5SAndroid Build Coastguard Worker }
687*8975f5c5SAndroid Build Coastguard Worker 
isVariableDeclared(const TVariable * variable)688*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::isVariableDeclared(const TVariable *variable)
689*8975f5c5SAndroid Build Coastguard Worker {
690*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mOptions.validateVariableReferences);
691*8975f5c5SAndroid Build Coastguard Worker 
692*8975f5c5SAndroid Build Coastguard Worker     for (const std::set<const TVariable *> &scopeVariables : mDeclaredVariables)
693*8975f5c5SAndroid Build Coastguard Worker     {
694*8975f5c5SAndroid Build Coastguard Worker         if (scopeVariables.count(variable) > 0)
695*8975f5c5SAndroid Build Coastguard Worker         {
696*8975f5c5SAndroid Build Coastguard Worker             return true;
697*8975f5c5SAndroid Build Coastguard Worker         }
698*8975f5c5SAndroid Build Coastguard Worker     }
699*8975f5c5SAndroid Build Coastguard Worker 
700*8975f5c5SAndroid Build Coastguard Worker     return false;
701*8975f5c5SAndroid Build Coastguard Worker }
702*8975f5c5SAndroid Build Coastguard Worker 
variableNeedsDeclaration(const TVariable * variable)703*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::variableNeedsDeclaration(const TVariable *variable)
704*8975f5c5SAndroid Build Coastguard Worker {
705*8975f5c5SAndroid Build Coastguard Worker     // Don't expect declaration for built-in variables.
706*8975f5c5SAndroid Build Coastguard Worker     if (gl::IsBuiltInName(variable->name().data()))
707*8975f5c5SAndroid Build Coastguard Worker     {
708*8975f5c5SAndroid Build Coastguard Worker         return false;
709*8975f5c5SAndroid Build Coastguard Worker     }
710*8975f5c5SAndroid Build Coastguard Worker 
711*8975f5c5SAndroid Build Coastguard Worker     // Additionally, don't expect declaration for Vulkan specialization constants if not enabled.
712*8975f5c5SAndroid Build Coastguard Worker     // The declaration of these variables is deferred.
713*8975f5c5SAndroid Build Coastguard Worker     if (variable->getType().getQualifier() == EvqSpecConst)
714*8975f5c5SAndroid Build Coastguard Worker     {
715*8975f5c5SAndroid Build Coastguard Worker         return mOptions.validateSpecConstReferences;
716*8975f5c5SAndroid Build Coastguard Worker     }
717*8975f5c5SAndroid Build Coastguard Worker 
718*8975f5c5SAndroid Build Coastguard Worker     return true;
719*8975f5c5SAndroid Build Coastguard Worker }
720*8975f5c5SAndroid Build Coastguard Worker 
getStructOrInterfaceBlock(const TType & type,Name * typeNameOut)721*8975f5c5SAndroid Build Coastguard Worker const TFieldListCollection *ValidateAST::getStructOrInterfaceBlock(const TType &type,
722*8975f5c5SAndroid Build Coastguard Worker                                                                    Name *typeNameOut)
723*8975f5c5SAndroid Build Coastguard Worker {
724*8975f5c5SAndroid Build Coastguard Worker     const TStructure *structure           = type.getStruct();
725*8975f5c5SAndroid Build Coastguard Worker     const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
726*8975f5c5SAndroid Build Coastguard Worker 
727*8975f5c5SAndroid Build Coastguard Worker     ASSERT(structure != nullptr || interfaceBlock != nullptr);
728*8975f5c5SAndroid Build Coastguard Worker 
729*8975f5c5SAndroid Build Coastguard Worker     // Make sure the structure or interface block is not doubly defined.
730*8975f5c5SAndroid Build Coastguard Worker     const TFieldListCollection *structOrBlock = nullptr;
731*8975f5c5SAndroid Build Coastguard Worker     if (structure != nullptr && structure->symbolType() != SymbolType::Empty)
732*8975f5c5SAndroid Build Coastguard Worker     {
733*8975f5c5SAndroid Build Coastguard Worker         structOrBlock = structure;
734*8975f5c5SAndroid Build Coastguard Worker         *typeNameOut  = Name(*structure);
735*8975f5c5SAndroid Build Coastguard Worker     }
736*8975f5c5SAndroid Build Coastguard Worker     else if (interfaceBlock != nullptr)
737*8975f5c5SAndroid Build Coastguard Worker     {
738*8975f5c5SAndroid Build Coastguard Worker         structOrBlock = interfaceBlock;
739*8975f5c5SAndroid Build Coastguard Worker         *typeNameOut  = Name(*interfaceBlock);
740*8975f5c5SAndroid Build Coastguard Worker     }
741*8975f5c5SAndroid Build Coastguard Worker 
742*8975f5c5SAndroid Build Coastguard Worker     return structOrBlock;
743*8975f5c5SAndroid Build Coastguard Worker }
744*8975f5c5SAndroid Build Coastguard Worker 
expectNonNullChildren(Visit visit,TIntermNode * node,size_t least_count)745*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::expectNonNullChildren(Visit visit, TIntermNode *node, size_t least_count)
746*8975f5c5SAndroid Build Coastguard Worker {
747*8975f5c5SAndroid Build Coastguard Worker     if (visit == PreVisit && mOptions.validateNullNodes)
748*8975f5c5SAndroid Build Coastguard Worker     {
749*8975f5c5SAndroid Build Coastguard Worker         size_t childCount = node->getChildCount();
750*8975f5c5SAndroid Build Coastguard Worker         if (childCount < least_count)
751*8975f5c5SAndroid Build Coastguard Worker         {
752*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(node->getLine(), "Too few children", "<validateNullNodes>");
753*8975f5c5SAndroid Build Coastguard Worker             mNullNodesFailed = true;
754*8975f5c5SAndroid Build Coastguard Worker         }
755*8975f5c5SAndroid Build Coastguard Worker 
756*8975f5c5SAndroid Build Coastguard Worker         for (size_t i = 0; i < childCount; ++i)
757*8975f5c5SAndroid Build Coastguard Worker         {
758*8975f5c5SAndroid Build Coastguard Worker             if (node->getChildNode(i) == nullptr)
759*8975f5c5SAndroid Build Coastguard Worker             {
760*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->error(node->getLine(), "Found nullptr child", "<validateNullNodes>");
761*8975f5c5SAndroid Build Coastguard Worker                 mNullNodesFailed = true;
762*8975f5c5SAndroid Build Coastguard Worker             }
763*8975f5c5SAndroid Build Coastguard Worker         }
764*8975f5c5SAndroid Build Coastguard Worker     }
765*8975f5c5SAndroid Build Coastguard Worker }
766*8975f5c5SAndroid Build Coastguard Worker 
visitSymbol(TIntermSymbol * node)767*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::visitSymbol(TIntermSymbol *node)
768*8975f5c5SAndroid Build Coastguard Worker {
769*8975f5c5SAndroid Build Coastguard Worker     visitNode(PreVisit, node);
770*8975f5c5SAndroid Build Coastguard Worker 
771*8975f5c5SAndroid Build Coastguard Worker     const TVariable *variable = &node->variable();
772*8975f5c5SAndroid Build Coastguard Worker 
773*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validateVariableReferences)
774*8975f5c5SAndroid Build Coastguard Worker     {
775*8975f5c5SAndroid Build Coastguard Worker         if (variableNeedsDeclaration(variable))
776*8975f5c5SAndroid Build Coastguard Worker         {
777*8975f5c5SAndroid Build Coastguard Worker             visitVariableNeedingDeclaration(node);
778*8975f5c5SAndroid Build Coastguard Worker         }
779*8975f5c5SAndroid Build Coastguard Worker     }
780*8975f5c5SAndroid Build Coastguard Worker     if (variable->symbolType() == SymbolType::Empty)
781*8975f5c5SAndroid Build Coastguard Worker     {
782*8975f5c5SAndroid Build Coastguard Worker         if (!isInDeclaration())
783*8975f5c5SAndroid Build Coastguard Worker         {
784*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(node->getLine(), "Found symbol with empty name", "");
785*8975f5c5SAndroid Build Coastguard Worker             mVariableNamingFailed = true;
786*8975f5c5SAndroid Build Coastguard Worker         }
787*8975f5c5SAndroid Build Coastguard Worker     }
788*8975f5c5SAndroid Build Coastguard Worker     const bool isBuiltIn = gl::IsBuiltInName(variable->name().data());
789*8975f5c5SAndroid Build Coastguard Worker     if (isBuiltIn)
790*8975f5c5SAndroid Build Coastguard Worker     {
791*8975f5c5SAndroid Build Coastguard Worker         visitBuiltInVariable(node);
792*8975f5c5SAndroid Build Coastguard Worker     }
793*8975f5c5SAndroid Build Coastguard Worker 
794*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validatePrecision)
795*8975f5c5SAndroid Build Coastguard Worker     {
796*8975f5c5SAndroid Build Coastguard Worker         if (!isBuiltIn && IsPrecisionApplicableToType(node->getBasicType()) &&
797*8975f5c5SAndroid Build Coastguard Worker             node->getType().getPrecision() == EbpUndefined)
798*8975f5c5SAndroid Build Coastguard Worker         {
799*8975f5c5SAndroid Build Coastguard Worker             // Note that some built-ins don't have a precision.
800*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(node->getLine(),
801*8975f5c5SAndroid Build Coastguard Worker                                 "Found symbol with undefined precision <validatePrecision>",
802*8975f5c5SAndroid Build Coastguard Worker                                 variable->name().data());
803*8975f5c5SAndroid Build Coastguard Worker             mPrecisionFailed = true;
804*8975f5c5SAndroid Build Coastguard Worker         }
805*8975f5c5SAndroid Build Coastguard Worker     }
806*8975f5c5SAndroid Build Coastguard Worker }
807*8975f5c5SAndroid Build Coastguard Worker 
visitConstantUnion(TIntermConstantUnion * node)808*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::visitConstantUnion(TIntermConstantUnion *node)
809*8975f5c5SAndroid Build Coastguard Worker {
810*8975f5c5SAndroid Build Coastguard Worker     visitNode(PreVisit, node);
811*8975f5c5SAndroid Build Coastguard Worker }
812*8975f5c5SAndroid Build Coastguard Worker 
visitSwizzle(Visit visit,TIntermSwizzle * node)813*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::visitSwizzle(Visit visit, TIntermSwizzle *node)
814*8975f5c5SAndroid Build Coastguard Worker {
815*8975f5c5SAndroid Build Coastguard Worker     visitNode(visit, node);
816*8975f5c5SAndroid Build Coastguard Worker 
817*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validateNoSwizzleOfSwizzle)
818*8975f5c5SAndroid Build Coastguard Worker     {
819*8975f5c5SAndroid Build Coastguard Worker         if (node->getOperand()->getAsSwizzleNode() != nullptr)
820*8975f5c5SAndroid Build Coastguard Worker         {
821*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(node->getLine(), "Found swizzle applied to swizzle",
822*8975f5c5SAndroid Build Coastguard Worker                                 "<validateNoSwizzleOfSwizzle>");
823*8975f5c5SAndroid Build Coastguard Worker             mNoSwizzleOfSwizzleFailed = true;
824*8975f5c5SAndroid Build Coastguard Worker         }
825*8975f5c5SAndroid Build Coastguard Worker     }
826*8975f5c5SAndroid Build Coastguard Worker 
827*8975f5c5SAndroid Build Coastguard Worker     return true;
828*8975f5c5SAndroid Build Coastguard Worker }
829*8975f5c5SAndroid Build Coastguard Worker 
visitBinary(Visit visit,TIntermBinary * node)830*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::visitBinary(Visit visit, TIntermBinary *node)
831*8975f5c5SAndroid Build Coastguard Worker {
832*8975f5c5SAndroid Build Coastguard Worker     visitNode(visit, node);
833*8975f5c5SAndroid Build Coastguard Worker 
834*8975f5c5SAndroid Build Coastguard Worker     if (visit == PreVisit && mOptions.validateOps)
835*8975f5c5SAndroid Build Coastguard Worker     {
836*8975f5c5SAndroid Build Coastguard Worker         const bool hasParent = getParentNode() != nullptr;
837*8975f5c5SAndroid Build Coastguard Worker         const bool isInDeclaration =
838*8975f5c5SAndroid Build Coastguard Worker             hasParent && getParentNode()->getAsDeclarationNode() != nullptr;
839*8975f5c5SAndroid Build Coastguard Worker         const TOperator op = node->getOp();
840*8975f5c5SAndroid Build Coastguard Worker         if (!BuiltInGroup::IsBuiltIn(op) && !IsBinaryOp(op))
841*8975f5c5SAndroid Build Coastguard Worker         {
842*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(node->getLine(),
843*8975f5c5SAndroid Build Coastguard Worker                                 "Found binary node with non-binary op <validateOps>",
844*8975f5c5SAndroid Build Coastguard Worker                                 GetOperatorString(op));
845*8975f5c5SAndroid Build Coastguard Worker             mOpsFailed = true;
846*8975f5c5SAndroid Build Coastguard Worker         }
847*8975f5c5SAndroid Build Coastguard Worker         else if (op == EOpInitialize && hasParent && !isInDeclaration)
848*8975f5c5SAndroid Build Coastguard Worker         {
849*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(node->getLine(),
850*8975f5c5SAndroid Build Coastguard Worker                                 "Found EOpInitialize node outside declaration <validateOps>",
851*8975f5c5SAndroid Build Coastguard Worker                                 GetOperatorString(op));
852*8975f5c5SAndroid Build Coastguard Worker             mOpsFailed = true;
853*8975f5c5SAndroid Build Coastguard Worker         }
854*8975f5c5SAndroid Build Coastguard Worker         else if (op == EOpAssign && hasParent && isInDeclaration)
855*8975f5c5SAndroid Build Coastguard Worker         {
856*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(node->getLine(),
857*8975f5c5SAndroid Build Coastguard Worker                                 "Found EOpAssign node inside declaration <validateOps>",
858*8975f5c5SAndroid Build Coastguard Worker                                 GetOperatorString(op));
859*8975f5c5SAndroid Build Coastguard Worker             mOpsFailed = true;
860*8975f5c5SAndroid Build Coastguard Worker         }
861*8975f5c5SAndroid Build Coastguard Worker     }
862*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validateExpressionTypes && visit == PreVisit)
863*8975f5c5SAndroid Build Coastguard Worker     {
864*8975f5c5SAndroid Build Coastguard Worker         validateExpressionTypeBinary(node);
865*8975f5c5SAndroid Build Coastguard Worker     }
866*8975f5c5SAndroid Build Coastguard Worker 
867*8975f5c5SAndroid Build Coastguard Worker     return true;
868*8975f5c5SAndroid Build Coastguard Worker }
869*8975f5c5SAndroid Build Coastguard Worker 
visitUnary(Visit visit,TIntermUnary * node)870*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::visitUnary(Visit visit, TIntermUnary *node)
871*8975f5c5SAndroid Build Coastguard Worker {
872*8975f5c5SAndroid Build Coastguard Worker     visitNode(visit, node);
873*8975f5c5SAndroid Build Coastguard Worker 
874*8975f5c5SAndroid Build Coastguard Worker     if (visit == PreVisit && mOptions.validateOps)
875*8975f5c5SAndroid Build Coastguard Worker     {
876*8975f5c5SAndroid Build Coastguard Worker         const TOperator op = node->getOp();
877*8975f5c5SAndroid Build Coastguard Worker         if (!BuiltInGroup::IsBuiltIn(op) && !IsUnaryOp(op))
878*8975f5c5SAndroid Build Coastguard Worker         {
879*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(node->getLine(), "Found unary node with non-unary op <validateOps>",
880*8975f5c5SAndroid Build Coastguard Worker                                 GetOperatorString(op));
881*8975f5c5SAndroid Build Coastguard Worker             mOpsFailed = true;
882*8975f5c5SAndroid Build Coastguard Worker         }
883*8975f5c5SAndroid Build Coastguard Worker     }
884*8975f5c5SAndroid Build Coastguard Worker     if (visit == PreVisit && mOptions.validateBuiltInOps)
885*8975f5c5SAndroid Build Coastguard Worker     {
886*8975f5c5SAndroid Build Coastguard Worker         visitBuiltInFunction(node, node->getFunction());
887*8975f5c5SAndroid Build Coastguard Worker     }
888*8975f5c5SAndroid Build Coastguard Worker 
889*8975f5c5SAndroid Build Coastguard Worker     return true;
890*8975f5c5SAndroid Build Coastguard Worker }
891*8975f5c5SAndroid Build Coastguard Worker 
visitTernary(Visit visit,TIntermTernary * node)892*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::visitTernary(Visit visit, TIntermTernary *node)
893*8975f5c5SAndroid Build Coastguard Worker {
894*8975f5c5SAndroid Build Coastguard Worker     visitNode(visit, node);
895*8975f5c5SAndroid Build Coastguard Worker     return true;
896*8975f5c5SAndroid Build Coastguard Worker }
897*8975f5c5SAndroid Build Coastguard Worker 
visitIfElse(Visit visit,TIntermIfElse * node)898*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::visitIfElse(Visit visit, TIntermIfElse *node)
899*8975f5c5SAndroid Build Coastguard Worker {
900*8975f5c5SAndroid Build Coastguard Worker     visitNode(visit, node);
901*8975f5c5SAndroid Build Coastguard Worker     return true;
902*8975f5c5SAndroid Build Coastguard Worker }
903*8975f5c5SAndroid Build Coastguard Worker 
visitSwitch(Visit visit,TIntermSwitch * node)904*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::visitSwitch(Visit visit, TIntermSwitch *node)
905*8975f5c5SAndroid Build Coastguard Worker {
906*8975f5c5SAndroid Build Coastguard Worker     visitNode(visit, node);
907*8975f5c5SAndroid Build Coastguard Worker 
908*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validateExpressionTypes && visit == PreVisit)
909*8975f5c5SAndroid Build Coastguard Worker     {
910*8975f5c5SAndroid Build Coastguard Worker         validateExpressionTypeSwitch(node);
911*8975f5c5SAndroid Build Coastguard Worker     }
912*8975f5c5SAndroid Build Coastguard Worker 
913*8975f5c5SAndroid Build Coastguard Worker     return true;
914*8975f5c5SAndroid Build Coastguard Worker }
915*8975f5c5SAndroid Build Coastguard Worker 
visitCase(Visit visit,TIntermCase * node)916*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::visitCase(Visit visit, TIntermCase *node)
917*8975f5c5SAndroid Build Coastguard Worker {
918*8975f5c5SAndroid Build Coastguard Worker     // Case is allowed to come after a branch, and for dead-code-elimination purposes acts as if a
919*8975f5c5SAndroid Build Coastguard Worker     // new block is started.
920*8975f5c5SAndroid Build Coastguard Worker     mIsBranchVisitedInBlock = false;
921*8975f5c5SAndroid Build Coastguard Worker 
922*8975f5c5SAndroid Build Coastguard Worker     visitNode(visit, node);
923*8975f5c5SAndroid Build Coastguard Worker 
924*8975f5c5SAndroid Build Coastguard Worker     return true;
925*8975f5c5SAndroid Build Coastguard Worker }
926*8975f5c5SAndroid Build Coastguard Worker 
visitFunctionPrototype(TIntermFunctionPrototype * node)927*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::visitFunctionPrototype(TIntermFunctionPrototype *node)
928*8975f5c5SAndroid Build Coastguard Worker {
929*8975f5c5SAndroid Build Coastguard Worker     visitNode(PreVisit, node);
930*8975f5c5SAndroid Build Coastguard Worker 
931*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validateFunctionCall)
932*8975f5c5SAndroid Build Coastguard Worker     {
933*8975f5c5SAndroid Build Coastguard Worker         const TFunction *function = node->getFunction();
934*8975f5c5SAndroid Build Coastguard Worker         mDeclaredFunctions.insert(function);
935*8975f5c5SAndroid Build Coastguard Worker     }
936*8975f5c5SAndroid Build Coastguard Worker 
937*8975f5c5SAndroid Build Coastguard Worker     const TFunction *function = node->getFunction();
938*8975f5c5SAndroid Build Coastguard Worker     const TType &returnType   = function->getReturnType();
939*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validatePrecision && IsPrecisionApplicableToType(returnType.getBasicType()) &&
940*8975f5c5SAndroid Build Coastguard Worker         returnType.getPrecision() == EbpUndefined)
941*8975f5c5SAndroid Build Coastguard Worker     {
942*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->error(
943*8975f5c5SAndroid Build Coastguard Worker             node->getLine(),
944*8975f5c5SAndroid Build Coastguard Worker             "Found function with undefined precision on return value <validatePrecision>",
945*8975f5c5SAndroid Build Coastguard Worker             function->name().data());
946*8975f5c5SAndroid Build Coastguard Worker         mPrecisionFailed = true;
947*8975f5c5SAndroid Build Coastguard Worker     }
948*8975f5c5SAndroid Build Coastguard Worker 
949*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validateStructUsage)
950*8975f5c5SAndroid Build Coastguard Worker     {
951*8975f5c5SAndroid Build Coastguard Worker         bool needsProcessing =
952*8975f5c5SAndroid Build Coastguard Worker             mStructUsageProcessedFunctions.find(function) == mStructUsageProcessedFunctions.end();
953*8975f5c5SAndroid Build Coastguard Worker         if (needsProcessing && returnType.isStructSpecifier())
954*8975f5c5SAndroid Build Coastguard Worker         {
955*8975f5c5SAndroid Build Coastguard Worker             visitStructOrInterfaceBlockDeclaration(returnType, node->getLine());
956*8975f5c5SAndroid Build Coastguard Worker             mStructUsageProcessedFunctions.insert(function);
957*8975f5c5SAndroid Build Coastguard Worker         }
958*8975f5c5SAndroid Build Coastguard Worker         else
959*8975f5c5SAndroid Build Coastguard Worker         {
960*8975f5c5SAndroid Build Coastguard Worker             visitStructUsage(returnType, node->getLine());
961*8975f5c5SAndroid Build Coastguard Worker         }
962*8975f5c5SAndroid Build Coastguard Worker     }
963*8975f5c5SAndroid Build Coastguard Worker 
964*8975f5c5SAndroid Build Coastguard Worker     for (size_t paramIndex = 0; paramIndex < function->getParamCount(); ++paramIndex)
965*8975f5c5SAndroid Build Coastguard Worker     {
966*8975f5c5SAndroid Build Coastguard Worker         const TVariable *param = function->getParam(paramIndex);
967*8975f5c5SAndroid Build Coastguard Worker         const TType &paramType = param->getType();
968*8975f5c5SAndroid Build Coastguard Worker 
969*8975f5c5SAndroid Build Coastguard Worker         if (mOptions.validateStructUsage)
970*8975f5c5SAndroid Build Coastguard Worker         {
971*8975f5c5SAndroid Build Coastguard Worker             visitStructUsage(paramType, node->getLine());
972*8975f5c5SAndroid Build Coastguard Worker         }
973*8975f5c5SAndroid Build Coastguard Worker 
974*8975f5c5SAndroid Build Coastguard Worker         if (mOptions.validateQualifiers)
975*8975f5c5SAndroid Build Coastguard Worker         {
976*8975f5c5SAndroid Build Coastguard Worker             TQualifier qualifier = paramType.getQualifier();
977*8975f5c5SAndroid Build Coastguard Worker             if (qualifier != EvqParamIn && qualifier != EvqParamOut && qualifier != EvqParamInOut &&
978*8975f5c5SAndroid Build Coastguard Worker                 qualifier != EvqParamConst)
979*8975f5c5SAndroid Build Coastguard Worker             {
980*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->error(node->getLine(),
981*8975f5c5SAndroid Build Coastguard Worker                                     "Found function prototype with an invalid qualifier "
982*8975f5c5SAndroid Build Coastguard Worker                                     "<validateQualifiers>",
983*8975f5c5SAndroid Build Coastguard Worker                                     param->name().data());
984*8975f5c5SAndroid Build Coastguard Worker                 mQualifiersFailed = true;
985*8975f5c5SAndroid Build Coastguard Worker             }
986*8975f5c5SAndroid Build Coastguard Worker 
987*8975f5c5SAndroid Build Coastguard Worker             if (IsOpaqueType(paramType.getBasicType()) && qualifier != EvqParamIn)
988*8975f5c5SAndroid Build Coastguard Worker             {
989*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->error(
990*8975f5c5SAndroid Build Coastguard Worker                     node->getLine(),
991*8975f5c5SAndroid Build Coastguard Worker                     "Found function prototype with an invalid qualifier on opaque parameter "
992*8975f5c5SAndroid Build Coastguard Worker                     "<validateQualifiers>",
993*8975f5c5SAndroid Build Coastguard Worker                     param->name().data());
994*8975f5c5SAndroid Build Coastguard Worker                 mQualifiersFailed = true;
995*8975f5c5SAndroid Build Coastguard Worker             }
996*8975f5c5SAndroid Build Coastguard Worker         }
997*8975f5c5SAndroid Build Coastguard Worker 
998*8975f5c5SAndroid Build Coastguard Worker         if (mOptions.validatePrecision && IsPrecisionApplicableToType(paramType.getBasicType()) &&
999*8975f5c5SAndroid Build Coastguard Worker             paramType.getPrecision() == EbpUndefined)
1000*8975f5c5SAndroid Build Coastguard Worker         {
1001*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(
1002*8975f5c5SAndroid Build Coastguard Worker                 node->getLine(),
1003*8975f5c5SAndroid Build Coastguard Worker                 "Found function parameter with undefined precision <validatePrecision>",
1004*8975f5c5SAndroid Build Coastguard Worker                 param->name().data());
1005*8975f5c5SAndroid Build Coastguard Worker             mPrecisionFailed = true;
1006*8975f5c5SAndroid Build Coastguard Worker         }
1007*8975f5c5SAndroid Build Coastguard Worker     }
1008*8975f5c5SAndroid Build Coastguard Worker }
1009*8975f5c5SAndroid Build Coastguard Worker 
visitFunctionDefinition(Visit visit,TIntermFunctionDefinition * node)1010*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
1011*8975f5c5SAndroid Build Coastguard Worker {
1012*8975f5c5SAndroid Build Coastguard Worker     visitNode(visit, node);
1013*8975f5c5SAndroid Build Coastguard Worker 
1014*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validateVariableReferences && visit == PreVisit)
1015*8975f5c5SAndroid Build Coastguard Worker     {
1016*8975f5c5SAndroid Build Coastguard Worker         const TFunction *function = node->getFunction();
1017*8975f5c5SAndroid Build Coastguard Worker 
1018*8975f5c5SAndroid Build Coastguard Worker         size_t paramCount = function->getParamCount();
1019*8975f5c5SAndroid Build Coastguard Worker         for (size_t paramIndex = 0; paramIndex < paramCount; ++paramIndex)
1020*8975f5c5SAndroid Build Coastguard Worker         {
1021*8975f5c5SAndroid Build Coastguard Worker             const TVariable *variable = function->getParam(paramIndex);
1022*8975f5c5SAndroid Build Coastguard Worker 
1023*8975f5c5SAndroid Build Coastguard Worker             if (isVariableDeclared(variable))
1024*8975f5c5SAndroid Build Coastguard Worker             {
1025*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->error(node->getLine(),
1026*8975f5c5SAndroid Build Coastguard Worker                                     "Found two declarations of the same function argument "
1027*8975f5c5SAndroid Build Coastguard Worker                                     "<validateVariableReferences>",
1028*8975f5c5SAndroid Build Coastguard Worker                                     variable->name().data());
1029*8975f5c5SAndroid Build Coastguard Worker                 mVariableReferencesFailed = true;
1030*8975f5c5SAndroid Build Coastguard Worker                 break;
1031*8975f5c5SAndroid Build Coastguard Worker             }
1032*8975f5c5SAndroid Build Coastguard Worker 
1033*8975f5c5SAndroid Build Coastguard Worker             mDeclaredVariables.back().insert(variable);
1034*8975f5c5SAndroid Build Coastguard Worker         }
1035*8975f5c5SAndroid Build Coastguard Worker     }
1036*8975f5c5SAndroid Build Coastguard Worker 
1037*8975f5c5SAndroid Build Coastguard Worker     return true;
1038*8975f5c5SAndroid Build Coastguard Worker }
1039*8975f5c5SAndroid Build Coastguard Worker 
visitAggregate(Visit visit,TIntermAggregate * node)1040*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::visitAggregate(Visit visit, TIntermAggregate *node)
1041*8975f5c5SAndroid Build Coastguard Worker {
1042*8975f5c5SAndroid Build Coastguard Worker     visitNode(visit, node);
1043*8975f5c5SAndroid Build Coastguard Worker     expectNonNullChildren(visit, node, 0);
1044*8975f5c5SAndroid Build Coastguard Worker 
1045*8975f5c5SAndroid Build Coastguard Worker     if (visit == PreVisit && mOptions.validateBuiltInOps)
1046*8975f5c5SAndroid Build Coastguard Worker     {
1047*8975f5c5SAndroid Build Coastguard Worker         visitBuiltInFunction(node, node->getFunction());
1048*8975f5c5SAndroid Build Coastguard Worker     }
1049*8975f5c5SAndroid Build Coastguard Worker 
1050*8975f5c5SAndroid Build Coastguard Worker     if (visit == PreVisit && mOptions.validateFunctionCall)
1051*8975f5c5SAndroid Build Coastguard Worker     {
1052*8975f5c5SAndroid Build Coastguard Worker         visitFunctionCall(node);
1053*8975f5c5SAndroid Build Coastguard Worker     }
1054*8975f5c5SAndroid Build Coastguard Worker 
1055*8975f5c5SAndroid Build Coastguard Worker     if (visit == PreVisit && mOptions.validateNoRawFunctionCalls)
1056*8975f5c5SAndroid Build Coastguard Worker     {
1057*8975f5c5SAndroid Build Coastguard Worker         if (node->getOp() == EOpCallInternalRawFunction)
1058*8975f5c5SAndroid Build Coastguard Worker         {
1059*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(node->getLine(),
1060*8975f5c5SAndroid Build Coastguard Worker                                 "Found node calling a raw function (deprecated) "
1061*8975f5c5SAndroid Build Coastguard Worker                                 "<validateNoRawFunctionCalls>",
1062*8975f5c5SAndroid Build Coastguard Worker                                 node->getFunction()->name().data());
1063*8975f5c5SAndroid Build Coastguard Worker             mNoRawFunctionCallsFailed = true;
1064*8975f5c5SAndroid Build Coastguard Worker         }
1065*8975f5c5SAndroid Build Coastguard Worker     }
1066*8975f5c5SAndroid Build Coastguard Worker 
1067*8975f5c5SAndroid Build Coastguard Worker     if (visit == PreVisit && mOptions.validateNoQualifiersOnConstructors)
1068*8975f5c5SAndroid Build Coastguard Worker     {
1069*8975f5c5SAndroid Build Coastguard Worker         if (node->getOp() == EOpConstruct)
1070*8975f5c5SAndroid Build Coastguard Worker         {
1071*8975f5c5SAndroid Build Coastguard Worker             if (node->getType().isInvariant())
1072*8975f5c5SAndroid Build Coastguard Worker             {
1073*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->error(node->getLine(), "Found constructor node with invariant type",
1074*8975f5c5SAndroid Build Coastguard Worker                                     "<validateNoQualifiersOnConstructors>");
1075*8975f5c5SAndroid Build Coastguard Worker                 mNoQualifiersOnConstructorsFailed = true;
1076*8975f5c5SAndroid Build Coastguard Worker             }
1077*8975f5c5SAndroid Build Coastguard Worker             if (node->getType().isPrecise())
1078*8975f5c5SAndroid Build Coastguard Worker             {
1079*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->error(node->getLine(), "Found constructor node with precise type",
1080*8975f5c5SAndroid Build Coastguard Worker                                     "<validateNoQualifiersOnConstructors>");
1081*8975f5c5SAndroid Build Coastguard Worker                 mNoQualifiersOnConstructorsFailed = true;
1082*8975f5c5SAndroid Build Coastguard Worker             }
1083*8975f5c5SAndroid Build Coastguard Worker             if (node->getType().isInterpolant())
1084*8975f5c5SAndroid Build Coastguard Worker             {
1085*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->error(node->getLine(), "Found constructor node with interpolant type",
1086*8975f5c5SAndroid Build Coastguard Worker                                     "<validateNoQualifiersOnConstructors>");
1087*8975f5c5SAndroid Build Coastguard Worker                 mNoQualifiersOnConstructorsFailed = true;
1088*8975f5c5SAndroid Build Coastguard Worker             }
1089*8975f5c5SAndroid Build Coastguard Worker             if (!node->getType().getMemoryQualifier().isEmpty())
1090*8975f5c5SAndroid Build Coastguard Worker             {
1091*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->error(node->getLine(),
1092*8975f5c5SAndroid Build Coastguard Worker                                     "Found constructor node whose type has a memory qualifier",
1093*8975f5c5SAndroid Build Coastguard Worker                                     "<validateNoQualifiersOnConstructors>");
1094*8975f5c5SAndroid Build Coastguard Worker                 mNoQualifiersOnConstructorsFailed = true;
1095*8975f5c5SAndroid Build Coastguard Worker             }
1096*8975f5c5SAndroid Build Coastguard Worker             if (node->getType().getInterfaceBlock() != nullptr)
1097*8975f5c5SAndroid Build Coastguard Worker             {
1098*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->error(
1099*8975f5c5SAndroid Build Coastguard Worker                     node->getLine(),
1100*8975f5c5SAndroid Build Coastguard Worker                     "Found constructor node whose type references an interface block",
1101*8975f5c5SAndroid Build Coastguard Worker                     "<validateNoQualifiersOnConstructors>");
1102*8975f5c5SAndroid Build Coastguard Worker                 mNoQualifiersOnConstructorsFailed = true;
1103*8975f5c5SAndroid Build Coastguard Worker             }
1104*8975f5c5SAndroid Build Coastguard Worker             if (!node->getType().getLayoutQualifier().isEmpty())
1105*8975f5c5SAndroid Build Coastguard Worker             {
1106*8975f5c5SAndroid Build Coastguard Worker                 mDiagnostics->error(node->getLine(),
1107*8975f5c5SAndroid Build Coastguard Worker                                     "Found constructor node whose type has a layout qualifier",
1108*8975f5c5SAndroid Build Coastguard Worker                                     "<validateNoQualifiersOnConstructors>");
1109*8975f5c5SAndroid Build Coastguard Worker                 mNoQualifiersOnConstructorsFailed = true;
1110*8975f5c5SAndroid Build Coastguard Worker             }
1111*8975f5c5SAndroid Build Coastguard Worker         }
1112*8975f5c5SAndroid Build Coastguard Worker     }
1113*8975f5c5SAndroid Build Coastguard Worker 
1114*8975f5c5SAndroid Build Coastguard Worker     return true;
1115*8975f5c5SAndroid Build Coastguard Worker }
1116*8975f5c5SAndroid Build Coastguard Worker 
visitBlock(Visit visit,TIntermBlock * node)1117*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::visitBlock(Visit visit, TIntermBlock *node)
1118*8975f5c5SAndroid Build Coastguard Worker {
1119*8975f5c5SAndroid Build Coastguard Worker     visitNode(visit, node);
1120*8975f5c5SAndroid Build Coastguard Worker     scope(visit);
1121*8975f5c5SAndroid Build Coastguard Worker     expectNonNullChildren(visit, node, 0);
1122*8975f5c5SAndroid Build Coastguard Worker 
1123*8975f5c5SAndroid Build Coastguard Worker     if (visit == PostVisit)
1124*8975f5c5SAndroid Build Coastguard Worker     {
1125*8975f5c5SAndroid Build Coastguard Worker         // If the parent is a block and mIsBranchVisitedInBlock is set, this is a nested block
1126*8975f5c5SAndroid Build Coastguard Worker         // without any condition (like if, loop or switch), so the rest of the parent block is also
1127*8975f5c5SAndroid Build Coastguard Worker         // dead code.  Otherwise the parent block can contain code after this.
1128*8975f5c5SAndroid Build Coastguard Worker         if (getParentNode() == nullptr || getParentNode()->getAsBlock() == nullptr)
1129*8975f5c5SAndroid Build Coastguard Worker         {
1130*8975f5c5SAndroid Build Coastguard Worker             mIsBranchVisitedInBlock = false;
1131*8975f5c5SAndroid Build Coastguard Worker         }
1132*8975f5c5SAndroid Build Coastguard Worker     }
1133*8975f5c5SAndroid Build Coastguard Worker 
1134*8975f5c5SAndroid Build Coastguard Worker     return true;
1135*8975f5c5SAndroid Build Coastguard Worker }
1136*8975f5c5SAndroid Build Coastguard Worker 
visitGlobalQualifierDeclaration(Visit visit,TIntermGlobalQualifierDeclaration * node)1137*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::visitGlobalQualifierDeclaration(Visit visit,
1138*8975f5c5SAndroid Build Coastguard Worker                                                   TIntermGlobalQualifierDeclaration *node)
1139*8975f5c5SAndroid Build Coastguard Worker {
1140*8975f5c5SAndroid Build Coastguard Worker     visitNode(visit, node);
1141*8975f5c5SAndroid Build Coastguard Worker 
1142*8975f5c5SAndroid Build Coastguard Worker     const TVariable *variable = &node->getSymbol()->variable();
1143*8975f5c5SAndroid Build Coastguard Worker 
1144*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validateVariableReferences && variableNeedsDeclaration(variable))
1145*8975f5c5SAndroid Build Coastguard Worker     {
1146*8975f5c5SAndroid Build Coastguard Worker         if (!isVariableDeclared(variable))
1147*8975f5c5SAndroid Build Coastguard Worker         {
1148*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(node->getLine(),
1149*8975f5c5SAndroid Build Coastguard Worker                                 "Found reference to undeclared or inconsistently transformed "
1150*8975f5c5SAndroid Build Coastguard Worker                                 "variable <validateVariableReferences>",
1151*8975f5c5SAndroid Build Coastguard Worker                                 variable->name().data());
1152*8975f5c5SAndroid Build Coastguard Worker             mVariableReferencesFailed = true;
1153*8975f5c5SAndroid Build Coastguard Worker         }
1154*8975f5c5SAndroid Build Coastguard Worker     }
1155*8975f5c5SAndroid Build Coastguard Worker     return true;
1156*8975f5c5SAndroid Build Coastguard Worker }
1157*8975f5c5SAndroid Build Coastguard Worker 
visitDeclaration(Visit visit,TIntermDeclaration * node)1158*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::visitDeclaration(Visit visit, TIntermDeclaration *node)
1159*8975f5c5SAndroid Build Coastguard Worker {
1160*8975f5c5SAndroid Build Coastguard Worker     visitNode(visit, node);
1161*8975f5c5SAndroid Build Coastguard Worker     expectNonNullChildren(visit, node, 0);
1162*8975f5c5SAndroid Build Coastguard Worker 
1163*8975f5c5SAndroid Build Coastguard Worker     const TIntermSequence &sequence = *(node->getSequence());
1164*8975f5c5SAndroid Build Coastguard Worker 
1165*8975f5c5SAndroid Build Coastguard Worker     if (mOptions.validateMultiDeclarations && sequence.size() > 1)
1166*8975f5c5SAndroid Build Coastguard Worker     {
1167*8975f5c5SAndroid Build Coastguard Worker         TIntermSymbol *symbol = sequence[1]->getAsSymbolNode();
1168*8975f5c5SAndroid Build Coastguard Worker         if (symbol == nullptr)
1169*8975f5c5SAndroid Build Coastguard Worker         {
1170*8975f5c5SAndroid Build Coastguard Worker             TIntermBinary *init = sequence[1]->getAsBinaryNode();
1171*8975f5c5SAndroid Build Coastguard Worker             ASSERT(init && init->getOp() == EOpInitialize);
1172*8975f5c5SAndroid Build Coastguard Worker             symbol = init->getLeft()->getAsSymbolNode();
1173*8975f5c5SAndroid Build Coastguard Worker         }
1174*8975f5c5SAndroid Build Coastguard Worker         ASSERT(symbol);
1175*8975f5c5SAndroid Build Coastguard Worker 
1176*8975f5c5SAndroid Build Coastguard Worker         mDiagnostics->error(node->getLine(),
1177*8975f5c5SAndroid Build Coastguard Worker                             "Found multiple declarations where SeparateDeclarations should have "
1178*8975f5c5SAndroid Build Coastguard Worker                             "separated them <validateMultiDeclarations>",
1179*8975f5c5SAndroid Build Coastguard Worker                             symbol->variable().name().data());
1180*8975f5c5SAndroid Build Coastguard Worker         mMultiDeclarationsFailed = true;
1181*8975f5c5SAndroid Build Coastguard Worker     }
1182*8975f5c5SAndroid Build Coastguard Worker 
1183*8975f5c5SAndroid Build Coastguard Worker     if (visit == PreVisit)
1184*8975f5c5SAndroid Build Coastguard Worker     {
1185*8975f5c5SAndroid Build Coastguard Worker         bool validateStructUsage = mOptions.validateStructUsage;
1186*8975f5c5SAndroid Build Coastguard Worker 
1187*8975f5c5SAndroid Build Coastguard Worker         for (TIntermNode *instance : sequence)
1188*8975f5c5SAndroid Build Coastguard Worker         {
1189*8975f5c5SAndroid Build Coastguard Worker             TIntermSymbol *symbol = instance->getAsSymbolNode();
1190*8975f5c5SAndroid Build Coastguard Worker             if (symbol == nullptr)
1191*8975f5c5SAndroid Build Coastguard Worker             {
1192*8975f5c5SAndroid Build Coastguard Worker                 TIntermBinary *init = instance->getAsBinaryNode();
1193*8975f5c5SAndroid Build Coastguard Worker                 ASSERT(init && init->getOp() == EOpInitialize);
1194*8975f5c5SAndroid Build Coastguard Worker                 symbol = init->getLeft()->getAsSymbolNode();
1195*8975f5c5SAndroid Build Coastguard Worker             }
1196*8975f5c5SAndroid Build Coastguard Worker             ASSERT(symbol);
1197*8975f5c5SAndroid Build Coastguard Worker 
1198*8975f5c5SAndroid Build Coastguard Worker             const TVariable *variable = &symbol->variable();
1199*8975f5c5SAndroid Build Coastguard Worker             const TType &type         = variable->getType();
1200*8975f5c5SAndroid Build Coastguard Worker 
1201*8975f5c5SAndroid Build Coastguard Worker             if (mOptions.validateVariableReferences)
1202*8975f5c5SAndroid Build Coastguard Worker             {
1203*8975f5c5SAndroid Build Coastguard Worker                 if (isVariableDeclared(variable))
1204*8975f5c5SAndroid Build Coastguard Worker                 {
1205*8975f5c5SAndroid Build Coastguard Worker                     mDiagnostics->error(
1206*8975f5c5SAndroid Build Coastguard Worker                         node->getLine(),
1207*8975f5c5SAndroid Build Coastguard Worker                         "Found two declarations of the same variable <validateVariableReferences>",
1208*8975f5c5SAndroid Build Coastguard Worker                         variable->name().data());
1209*8975f5c5SAndroid Build Coastguard Worker                     mVariableReferencesFailed = true;
1210*8975f5c5SAndroid Build Coastguard Worker                     break;
1211*8975f5c5SAndroid Build Coastguard Worker                 }
1212*8975f5c5SAndroid Build Coastguard Worker 
1213*8975f5c5SAndroid Build Coastguard Worker                 mDeclaredVariables.back().insert(variable);
1214*8975f5c5SAndroid Build Coastguard Worker 
1215*8975f5c5SAndroid Build Coastguard Worker                 const TInterfaceBlock *interfaceBlock = variable->getType().getInterfaceBlock();
1216*8975f5c5SAndroid Build Coastguard Worker 
1217*8975f5c5SAndroid Build Coastguard Worker                 if (variable->symbolType() == SymbolType::Empty && interfaceBlock != nullptr)
1218*8975f5c5SAndroid Build Coastguard Worker                 {
1219*8975f5c5SAndroid Build Coastguard Worker                     // Nameless interface blocks can only be declared at the top level.  Their
1220*8975f5c5SAndroid Build Coastguard Worker                     // fields are matched by field index, and then verified to match by name.
1221*8975f5c5SAndroid Build Coastguard Worker                     // Conflict in names should have already generated a compile error.
1222*8975f5c5SAndroid Build Coastguard Worker                     ASSERT(mDeclaredVariables.size() == 1);
1223*8975f5c5SAndroid Build Coastguard Worker                     ASSERT(mNamelessInterfaceBlocks.count(interfaceBlock) == 0);
1224*8975f5c5SAndroid Build Coastguard Worker 
1225*8975f5c5SAndroid Build Coastguard Worker                     mNamelessInterfaceBlocks.insert(interfaceBlock);
1226*8975f5c5SAndroid Build Coastguard Worker                 }
1227*8975f5c5SAndroid Build Coastguard Worker             }
1228*8975f5c5SAndroid Build Coastguard Worker 
1229*8975f5c5SAndroid Build Coastguard Worker             if (validateStructUsage)
1230*8975f5c5SAndroid Build Coastguard Worker             {
1231*8975f5c5SAndroid Build Coastguard Worker                 // Only declare and/or validate the struct once.
1232*8975f5c5SAndroid Build Coastguard Worker                 validateStructUsage = false;
1233*8975f5c5SAndroid Build Coastguard Worker 
1234*8975f5c5SAndroid Build Coastguard Worker                 if (type.isStructSpecifier() || type.isInterfaceBlock())
1235*8975f5c5SAndroid Build Coastguard Worker                 {
1236*8975f5c5SAndroid Build Coastguard Worker                     visitStructOrInterfaceBlockDeclaration(type, node->getLine());
1237*8975f5c5SAndroid Build Coastguard Worker                 }
1238*8975f5c5SAndroid Build Coastguard Worker                 else
1239*8975f5c5SAndroid Build Coastguard Worker                 {
1240*8975f5c5SAndroid Build Coastguard Worker                     visitStructUsage(type, node->getLine());
1241*8975f5c5SAndroid Build Coastguard Worker                 }
1242*8975f5c5SAndroid Build Coastguard Worker             }
1243*8975f5c5SAndroid Build Coastguard Worker 
1244*8975f5c5SAndroid Build Coastguard Worker             if (gl::IsBuiltInName(variable->name().data()))
1245*8975f5c5SAndroid Build Coastguard Worker             {
1246*8975f5c5SAndroid Build Coastguard Worker                 visitBuiltInVariable(symbol);
1247*8975f5c5SAndroid Build Coastguard Worker             }
1248*8975f5c5SAndroid Build Coastguard Worker 
1249*8975f5c5SAndroid Build Coastguard Worker             if (mOptions.validatePrecision && (type.isStructSpecifier() || type.isInterfaceBlock()))
1250*8975f5c5SAndroid Build Coastguard Worker             {
1251*8975f5c5SAndroid Build Coastguard Worker                 const TFieldListCollection *structOrBlock = type.getStruct();
1252*8975f5c5SAndroid Build Coastguard Worker                 if (structOrBlock == nullptr)
1253*8975f5c5SAndroid Build Coastguard Worker                 {
1254*8975f5c5SAndroid Build Coastguard Worker                     structOrBlock = type.getInterfaceBlock();
1255*8975f5c5SAndroid Build Coastguard Worker                 }
1256*8975f5c5SAndroid Build Coastguard Worker 
1257*8975f5c5SAndroid Build Coastguard Worker                 for (const TField *field : structOrBlock->fields())
1258*8975f5c5SAndroid Build Coastguard Worker                 {
1259*8975f5c5SAndroid Build Coastguard Worker                     const TType *fieldType = field->type();
1260*8975f5c5SAndroid Build Coastguard Worker                     if (IsPrecisionApplicableToType(fieldType->getBasicType()) &&
1261*8975f5c5SAndroid Build Coastguard Worker                         fieldType->getPrecision() == EbpUndefined)
1262*8975f5c5SAndroid Build Coastguard Worker                     {
1263*8975f5c5SAndroid Build Coastguard Worker                         mDiagnostics->error(
1264*8975f5c5SAndroid Build Coastguard Worker                             node->getLine(),
1265*8975f5c5SAndroid Build Coastguard Worker                             "Found block field with undefined precision <validatePrecision>",
1266*8975f5c5SAndroid Build Coastguard Worker                             field->name().data());
1267*8975f5c5SAndroid Build Coastguard Worker                         mPrecisionFailed = true;
1268*8975f5c5SAndroid Build Coastguard Worker                     }
1269*8975f5c5SAndroid Build Coastguard Worker                 }
1270*8975f5c5SAndroid Build Coastguard Worker             }
1271*8975f5c5SAndroid Build Coastguard Worker         }
1272*8975f5c5SAndroid Build Coastguard Worker     }
1273*8975f5c5SAndroid Build Coastguard Worker 
1274*8975f5c5SAndroid Build Coastguard Worker     return true;
1275*8975f5c5SAndroid Build Coastguard Worker }
1276*8975f5c5SAndroid Build Coastguard Worker 
visitLoop(Visit visit,TIntermLoop * node)1277*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::visitLoop(Visit visit, TIntermLoop *node)
1278*8975f5c5SAndroid Build Coastguard Worker {
1279*8975f5c5SAndroid Build Coastguard Worker     visitNode(visit, node);
1280*8975f5c5SAndroid Build Coastguard Worker     return true;
1281*8975f5c5SAndroid Build Coastguard Worker }
1282*8975f5c5SAndroid Build Coastguard Worker 
visitBranch(Visit visit,TIntermBranch * node)1283*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::visitBranch(Visit visit, TIntermBranch *node)
1284*8975f5c5SAndroid Build Coastguard Worker {
1285*8975f5c5SAndroid Build Coastguard Worker     visitNode(visit, node);
1286*8975f5c5SAndroid Build Coastguard Worker 
1287*8975f5c5SAndroid Build Coastguard Worker     if (visit == PreVisit && mOptions.validateOps)
1288*8975f5c5SAndroid Build Coastguard Worker     {
1289*8975f5c5SAndroid Build Coastguard Worker         const TOperator op = node->getFlowOp();
1290*8975f5c5SAndroid Build Coastguard Worker         if (!IsBranchOp(op))
1291*8975f5c5SAndroid Build Coastguard Worker         {
1292*8975f5c5SAndroid Build Coastguard Worker             mDiagnostics->error(node->getLine(),
1293*8975f5c5SAndroid Build Coastguard Worker                                 "Found branch node with non-branch op <validateOps>",
1294*8975f5c5SAndroid Build Coastguard Worker                                 GetOperatorString(op));
1295*8975f5c5SAndroid Build Coastguard Worker             mOpsFailed = true;
1296*8975f5c5SAndroid Build Coastguard Worker         }
1297*8975f5c5SAndroid Build Coastguard Worker     }
1298*8975f5c5SAndroid Build Coastguard Worker     if (visit == PostVisit)
1299*8975f5c5SAndroid Build Coastguard Worker     {
1300*8975f5c5SAndroid Build Coastguard Worker         mIsBranchVisitedInBlock = true;
1301*8975f5c5SAndroid Build Coastguard Worker     }
1302*8975f5c5SAndroid Build Coastguard Worker 
1303*8975f5c5SAndroid Build Coastguard Worker     return true;
1304*8975f5c5SAndroid Build Coastguard Worker }
1305*8975f5c5SAndroid Build Coastguard Worker 
visitPreprocessorDirective(TIntermPreprocessorDirective * node)1306*8975f5c5SAndroid Build Coastguard Worker void ValidateAST::visitPreprocessorDirective(TIntermPreprocessorDirective *node)
1307*8975f5c5SAndroid Build Coastguard Worker {
1308*8975f5c5SAndroid Build Coastguard Worker     visitNode(PreVisit, node);
1309*8975f5c5SAndroid Build Coastguard Worker }
1310*8975f5c5SAndroid Build Coastguard Worker 
validateInternal()1311*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::validateInternal()
1312*8975f5c5SAndroid Build Coastguard Worker {
1313*8975f5c5SAndroid Build Coastguard Worker     return !mSingleParentFailed && !mVariableReferencesFailed && !mOpsFailed &&
1314*8975f5c5SAndroid Build Coastguard Worker            !mBuiltInOpsFailed && !mFunctionCallFailed && !mNoRawFunctionCallsFailed &&
1315*8975f5c5SAndroid Build Coastguard Worker            !mNullNodesFailed && !mQualifiersFailed && !mPrecisionFailed && !mStructUsageFailed &&
1316*8975f5c5SAndroid Build Coastguard Worker            !mExpressionTypesFailed && !mMultiDeclarationsFailed && !mNoSwizzleOfSwizzleFailed &&
1317*8975f5c5SAndroid Build Coastguard Worker            !mNoQualifiersOnConstructorsFailed && !mNoStatementsAfterBranchFailed &&
1318*8975f5c5SAndroid Build Coastguard Worker            !mVariableNamingFailed;
1319*8975f5c5SAndroid Build Coastguard Worker }
1320*8975f5c5SAndroid Build Coastguard Worker 
isInDeclaration() const1321*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST::isInDeclaration() const
1322*8975f5c5SAndroid Build Coastguard Worker {
1323*8975f5c5SAndroid Build Coastguard Worker     auto *parent = getParentNode();
1324*8975f5c5SAndroid Build Coastguard Worker     return parent != nullptr && parent->getAsDeclarationNode() != nullptr;
1325*8975f5c5SAndroid Build Coastguard Worker }
1326*8975f5c5SAndroid Build Coastguard Worker 
1327*8975f5c5SAndroid Build Coastguard Worker }  // anonymous namespace
1328*8975f5c5SAndroid Build Coastguard Worker 
ValidateAST(TIntermNode * root,TDiagnostics * diagnostics,const ValidateASTOptions & options)1329*8975f5c5SAndroid Build Coastguard Worker bool ValidateAST(TIntermNode *root, TDiagnostics *diagnostics, const ValidateASTOptions &options)
1330*8975f5c5SAndroid Build Coastguard Worker {
1331*8975f5c5SAndroid Build Coastguard Worker     // ValidateAST is called after transformations, so if |validateNoMoreTransformations| is set,
1332*8975f5c5SAndroid Build Coastguard Worker     // it's immediately an error.
1333*8975f5c5SAndroid Build Coastguard Worker     if (options.validateNoMoreTransformations)
1334*8975f5c5SAndroid Build Coastguard Worker     {
1335*8975f5c5SAndroid Build Coastguard Worker         diagnostics->error(kNoSourceLoc, "Unexpected transformation after AST post-processing",
1336*8975f5c5SAndroid Build Coastguard Worker                            "<validateNoMoreTransformations>");
1337*8975f5c5SAndroid Build Coastguard Worker         return false;
1338*8975f5c5SAndroid Build Coastguard Worker     }
1339*8975f5c5SAndroid Build Coastguard Worker 
1340*8975f5c5SAndroid Build Coastguard Worker     return ValidateAST::validate(root, diagnostics, options);
1341*8975f5c5SAndroid Build Coastguard Worker }
1342*8975f5c5SAndroid Build Coastguard Worker 
1343*8975f5c5SAndroid Build Coastguard Worker }  // namespace sh
1344