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 ¶mType = 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