blob: b5cb02439bbf30d1e67db147b9495f95f40da0f4 [file] [log] [blame]
Stephen Hines11274a72012-09-26 19:14:20 -07001/*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "slang_rs_check_ast.h"
18
19#include "slang_assert.h"
20#include "slang_rs.h"
Stephen Hines089cde32012-12-07 19:19:10 -080021#include "slang_rs_export_foreach.h"
Stephen Hines11274a72012-09-26 19:14:20 -070022#include "slang_rs_export_type.h"
23
24namespace slang {
25
26void RSCheckAST::VisitStmt(clang::Stmt *S) {
27 // This function does the actual iteration through all sub-Stmt's within
28 // a given Stmt. Note that this function is skipped by all of the other
29 // Visit* functions if we have already found a higher-level match.
30 for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
31 I != E;
32 I++) {
33 if (clang::Stmt *Child = *I) {
34 Visit(Child);
35 }
36 }
37}
38
Tobias Grosser61685432013-07-31 14:52:24 -070039void RSCheckAST::WarnOnSetElementAt(clang::CallExpr *E) {
40 clang::FunctionDecl *Decl;
Tobias Grosser61685432013-07-31 14:52:24 -070041 Decl = clang::dyn_cast_or_null<clang::FunctionDecl>(E->getCalleeDecl());
42
43 if (!Decl || Decl->getNameAsString() != std::string("rsSetElementAt")) {
44 return;
45 }
46
47 clang::Expr *Expr;
48 clang::ImplicitCastExpr *ImplCast;
49 Expr = E->getArg(1);
50 ImplCast = clang::dyn_cast_or_null<clang::ImplicitCastExpr>(Expr);
51
52 if (!ImplCast) {
53 return;
54 }
55
56 const clang::Type *Ty;
57 const clang::VectorType *VectorTy;
58 const clang::BuiltinType *ElementTy;
59 Ty = ImplCast->getSubExpr()->getType()->getPointeeType()
60 ->getUnqualifiedDesugaredType();
61 VectorTy = clang::dyn_cast_or_null<clang::VectorType>(Ty);
62
63 if (VectorTy) {
64 ElementTy = clang::dyn_cast_or_null<clang::BuiltinType>(
65 VectorTy->getElementType()->getUnqualifiedDesugaredType());
66 } else {
67 ElementTy = clang::dyn_cast_or_null<clang::BuiltinType>(
68 Ty->getUnqualifiedDesugaredType());
69 }
70
71 if (!ElementTy) {
72 return;
73 }
74
75 // We only support vectors with 2, 3 or 4 elements.
76 if (VectorTy) {
77 switch (VectorTy->getNumElements()) {
78 default:
79 return;
80 case 2:
81 case 3:
82 case 4:
83 break;
84 }
85 }
86
87 const char *Name;
88
89 switch (ElementTy->getKind()) {
90 case clang::BuiltinType::Float:
91 Name = "float";
92 break;
93 case clang::BuiltinType::Double:
94 Name = "double";
95 break;
96 case clang::BuiltinType::Char_S:
97 Name = "char";
98 break;
99 case clang::BuiltinType::Short:
100 Name = "short";
101 break;
102 case clang::BuiltinType::Int:
103 Name = "int";
104 break;
105 case clang::BuiltinType::Long:
106 Name = "long";
107 break;
108 case clang::BuiltinType::UChar:
109 Name = "uchar";
110 break;
111 case clang::BuiltinType::UShort:
112 Name = "ushort";
113 break;
114 case clang::BuiltinType::UInt:
115 Name = "uint";
116 break;
117 case clang::BuiltinType::ULong:
118 Name = "ulong";
119 break;
120 default:
121 return;
122 }
123
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800124 clang::DiagnosticBuilder DiagBuilder =
125 Context->ReportWarning(E->getLocStart(),
126 "untyped rsSetElementAt() can reduce performance. "
127 "Use rsSetElementAt_%0%1() instead.");
Tobias Grosser61685432013-07-31 14:52:24 -0700128 DiagBuilder << Name;
129
130 if (VectorTy) {
131 DiagBuilder << VectorTy->getNumElements();
132 } else {
133 DiagBuilder << "";
134 }
Tobias Grosser61685432013-07-31 14:52:24 -0700135}
136
137void RSCheckAST::VisitCallExpr(clang::CallExpr *E) {
138 WarnOnSetElementAt(E);
139
140 for (clang::CallExpr::arg_iterator AI = E->arg_begin(), AE = E->arg_end();
141 AI != AE; ++AI) {
142 Visit(*AI);
143 }
144}
145
Stephen Hines11274a72012-09-26 19:14:20 -0700146void RSCheckAST::ValidateFunctionDecl(clang::FunctionDecl *FD) {
147 if (!FD) {
148 return;
149 }
150
Stephen Hines089cde32012-12-07 19:19:10 -0800151 if (mIsFilterscript) {
152 // Validate parameters for Filterscript.
153 size_t numParams = FD->getNumParams();
Stephen Hines11274a72012-09-26 19:14:20 -0700154
Tim Murrayee4016d2014-04-10 15:49:08 -0700155 clang::QualType resultType = FD->getReturnType().getCanonicalType();
Stephen Hines11274a72012-09-26 19:14:20 -0700156
Stephen Hines089cde32012-12-07 19:19:10 -0800157 // We use FD as our NamedDecl in the case of a bad return type.
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800158 if (!RSExportType::ValidateType(Context, C, resultType, FD,
Stephen Hines089cde32012-12-07 19:19:10 -0800159 FD->getLocStart(), mTargetAPI,
160 mIsFilterscript)) {
Stephen Hines11274a72012-09-26 19:14:20 -0700161 mValid = false;
162 }
Stephen Hines089cde32012-12-07 19:19:10 -0800163
164 for (size_t i = 0; i < numParams; i++) {
165 clang::ParmVarDecl *PVD = FD->getParamDecl(i);
166 clang::QualType QT = PVD->getType().getCanonicalType();
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800167 if (!RSExportType::ValidateType(Context, C, QT, PVD, PVD->getLocStart(),
Stephen Hines089cde32012-12-07 19:19:10 -0800168 mTargetAPI, mIsFilterscript)) {
169 mValid = false;
170 }
171 }
Stephen Hines11274a72012-09-26 19:14:20 -0700172 }
173
Stephen Hines089cde32012-12-07 19:19:10 -0800174 bool saveKernel = mInKernel;
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800175 mInKernel = RSExportForEach::isRSForEachFunc(mTargetAPI, Context, FD);
Stephen Hines089cde32012-12-07 19:19:10 -0800176
Stephen Hines11274a72012-09-26 19:14:20 -0700177 if (clang::Stmt *Body = FD->getBody()) {
178 Visit(Body);
179 }
Stephen Hines089cde32012-12-07 19:19:10 -0800180
181 mInKernel = saveKernel;
Stephen Hines11274a72012-09-26 19:14:20 -0700182}
183
184
185void RSCheckAST::ValidateVarDecl(clang::VarDecl *VD) {
186 if (!VD) {
187 return;
188 }
189
Stephen Hines089cde32012-12-07 19:19:10 -0800190 clang::QualType QT = VD->getType();
Stephen Hines11274a72012-09-26 19:14:20 -0700191
Stephen Hines44f10062013-06-13 00:33:23 -0700192 if (VD->getFormalLinkage() == clang::ExternalLinkage) {
Stephen Hines11274a72012-09-26 19:14:20 -0700193 llvm::StringRef TypeName;
Stephen Hines089cde32012-12-07 19:19:10 -0800194 const clang::Type *T = QT.getTypePtr();
Stephen Hines48d893d2013-12-06 18:00:27 -0800195 if (!RSExportType::NormalizeType(T, TypeName, Context, VD)) {
Stephen Hines11274a72012-09-26 19:14:20 -0700196 mValid = false;
197 }
198 }
199
Stephen Hines089cde32012-12-07 19:19:10 -0800200 // We don't allow static (non-const) variables within kernels.
201 if (mInKernel && VD->isStaticLocal()) {
202 if (!QT.isConstQualified()) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800203 Context->ReportError(
204 VD->getLocation(),
205 "Non-const static variables are not allowed in kernels: '%0'")
Stephen Hines089cde32012-12-07 19:19:10 -0800206 << VD->getName();
207 mValid = false;
208 }
209 }
210
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800211 if (!RSExportType::ValidateVarDecl(Context, VD, mTargetAPI, mIsFilterscript)) {
Stephen Hines11274a72012-09-26 19:14:20 -0700212 mValid = false;
213 } else if (clang::Expr *Init = VD->getInit()) {
214 // Only check the initializer if the decl is already ok.
215 Visit(Init);
216 }
217}
218
219
220void RSCheckAST::VisitDeclStmt(clang::DeclStmt *DS) {
221 if (!SlangRS::IsLocInRSHeaderFile(DS->getLocStart(), mSM)) {
222 for (clang::DeclStmt::decl_iterator I = DS->decl_begin(),
223 E = DS->decl_end();
224 I != E;
225 ++I) {
226 if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I)) {
227 ValidateVarDecl(VD);
228 } else if (clang::FunctionDecl *FD =
229 llvm::dyn_cast<clang::FunctionDecl>(*I)) {
230 ValidateFunctionDecl(FD);
231 }
232 }
233 }
234}
235
236
Stephen Hinesdbb6dc32013-05-08 13:43:13 -0700237void RSCheckAST::VisitCastExpr(clang::CastExpr *CE) {
238 if (CE->getCastKind() == clang::CK_BitCast) {
239 clang::QualType QT = CE->getType();
240 const clang::Type *T = QT.getTypePtr();
241 if (T->isVectorType()) {
Stephen Hinesdbb6dc32013-05-08 13:43:13 -0700242 if (llvm::isa<clang::ImplicitCastExpr>(CE)) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800243 Context->ReportError(CE->getExprLoc(), "invalid implicit vector cast");
Stephen Hinesdbb6dc32013-05-08 13:43:13 -0700244 } else {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800245 Context->ReportError(CE->getExprLoc(), "invalid vector cast");
Stephen Hinesdbb6dc32013-05-08 13:43:13 -0700246 }
247 mValid = false;
248 }
249 }
250 Visit(CE->getSubExpr());
251}
252
253
Stephen Hines11274a72012-09-26 19:14:20 -0700254void RSCheckAST::VisitExpr(clang::Expr *E) {
255 // This is where FS checks for code using pointer and/or 64-bit expressions
256 // (i.e. things like casts).
257
258 // First we skip implicit casts (things like function calls and explicit
259 // array accesses rely heavily on them and they are valid.
260 E = E->IgnoreImpCasts();
261 if (mIsFilterscript &&
262 !SlangRS::IsLocInRSHeaderFile(E->getExprLoc(), mSM) &&
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800263 !RSExportType::ValidateType(Context, C, E->getType(), NULL, E->getExprLoc(),
Stephen Hines11274a72012-09-26 19:14:20 -0700264 mTargetAPI, mIsFilterscript)) {
265 mValid = false;
266 } else {
267 // Only visit sub-expressions if we haven't already seen a violation.
268 VisitStmt(E);
269 }
270}
271
272
273bool RSCheckAST::Validate() {
274 clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
275 for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(),
276 DE = TUDecl->decls_end();
277 DI != DE;
278 DI++) {
279 if (!SlangRS::IsLocInRSHeaderFile(DI->getLocStart(), mSM)) {
280 if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*DI)) {
281 ValidateVarDecl(VD);
282 } else if (clang::FunctionDecl *FD =
283 llvm::dyn_cast<clang::FunctionDecl>(*DI)) {
284 ValidateFunctionDecl(FD);
285 } else if (clang::Stmt *Body = (*DI)->getBody()) {
286 Visit(Body);
287 }
288 }
289 }
290
291 return mValid;
292}
293
294} // namespace slang