blob: 7c96291f3f470861f4cee0f4397089613932c751 [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"
Jean-Luc Brouilletc10bc752015-05-04 23:02:25 -070020#include "slang.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 Hinese23d82b2015-06-11 17:00:04 -0700151 clang::QualType resultType = FD->getReturnType().getCanonicalType();
152 bool isExtern = (FD->getFormalLinkage() == clang::ExternalLinkage);
Stephen Hines11274a72012-09-26 19:14:20 -0700153
Stephen Hinese23d82b2015-06-11 17:00:04 -0700154 // We use FD as our NamedDecl in the case of a bad return type.
155 if (!RSExportType::ValidateType(Context, C, resultType, FD,
156 FD->getLocStart(), mTargetAPI,
157 mIsFilterscript, isExtern)) {
158 mValid = false;
159 }
Stephen Hines11274a72012-09-26 19:14:20 -0700160
Stephen Hinese23d82b2015-06-11 17:00:04 -0700161 size_t numParams = FD->getNumParams();
162 for (size_t i = 0; i < numParams; i++) {
163 clang::ParmVarDecl *PVD = FD->getParamDecl(i);
164 clang::QualType QT = PVD->getType().getCanonicalType();
165 if (!RSExportType::ValidateType(Context, C, QT, PVD, PVD->getLocStart(),
166 mTargetAPI, mIsFilterscript, isExtern)) {
Stephen Hines11274a72012-09-26 19:14:20 -0700167 mValid = false;
168 }
169 }
170
Stephen Hines089cde32012-12-07 19:19:10 -0800171 bool saveKernel = mInKernel;
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800172 mInKernel = RSExportForEach::isRSForEachFunc(mTargetAPI, Context, FD);
Stephen Hines089cde32012-12-07 19:19:10 -0800173
Stephen Hines11274a72012-09-26 19:14:20 -0700174 if (clang::Stmt *Body = FD->getBody()) {
175 Visit(Body);
176 }
Stephen Hines089cde32012-12-07 19:19:10 -0800177
178 mInKernel = saveKernel;
Stephen Hines11274a72012-09-26 19:14:20 -0700179}
180
181
182void RSCheckAST::ValidateVarDecl(clang::VarDecl *VD) {
183 if (!VD) {
184 return;
185 }
186
Stephen Hines089cde32012-12-07 19:19:10 -0800187 clang::QualType QT = VD->getType();
Stephen Hines11274a72012-09-26 19:14:20 -0700188
Stephen Hines44f10062013-06-13 00:33:23 -0700189 if (VD->getFormalLinkage() == clang::ExternalLinkage) {
Stephen Hines11274a72012-09-26 19:14:20 -0700190 llvm::StringRef TypeName;
Stephen Hines089cde32012-12-07 19:19:10 -0800191 const clang::Type *T = QT.getTypePtr();
Stephen Hines48d893d2013-12-06 18:00:27 -0800192 if (!RSExportType::NormalizeType(T, TypeName, Context, VD)) {
Stephen Hines11274a72012-09-26 19:14:20 -0700193 mValid = false;
194 }
195 }
196
Stephen Hines089cde32012-12-07 19:19:10 -0800197 // We don't allow static (non-const) variables within kernels.
198 if (mInKernel && VD->isStaticLocal()) {
199 if (!QT.isConstQualified()) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800200 Context->ReportError(
201 VD->getLocation(),
202 "Non-const static variables are not allowed in kernels: '%0'")
Stephen Hines089cde32012-12-07 19:19:10 -0800203 << VD->getName();
204 mValid = false;
205 }
206 }
207
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800208 if (!RSExportType::ValidateVarDecl(Context, VD, mTargetAPI, mIsFilterscript)) {
Stephen Hines11274a72012-09-26 19:14:20 -0700209 mValid = false;
210 } else if (clang::Expr *Init = VD->getInit()) {
211 // Only check the initializer if the decl is already ok.
212 Visit(Init);
213 }
214}
215
216
217void RSCheckAST::VisitDeclStmt(clang::DeclStmt *DS) {
Jean-Luc Brouilletc10bc752015-05-04 23:02:25 -0700218 if (!Slang::IsLocInRSHeaderFile(DS->getLocStart(), mSM)) {
Stephen Hines11274a72012-09-26 19:14:20 -0700219 for (clang::DeclStmt::decl_iterator I = DS->decl_begin(),
220 E = DS->decl_end();
221 I != E;
222 ++I) {
223 if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I)) {
224 ValidateVarDecl(VD);
225 } else if (clang::FunctionDecl *FD =
226 llvm::dyn_cast<clang::FunctionDecl>(*I)) {
227 ValidateFunctionDecl(FD);
228 }
229 }
230 }
231}
232
233
Stephen Hinesdbb6dc32013-05-08 13:43:13 -0700234void RSCheckAST::VisitCastExpr(clang::CastExpr *CE) {
235 if (CE->getCastKind() == clang::CK_BitCast) {
236 clang::QualType QT = CE->getType();
237 const clang::Type *T = QT.getTypePtr();
238 if (T->isVectorType()) {
Stephen Hinesdbb6dc32013-05-08 13:43:13 -0700239 if (llvm::isa<clang::ImplicitCastExpr>(CE)) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800240 Context->ReportError(CE->getExprLoc(), "invalid implicit vector cast");
Stephen Hinesdbb6dc32013-05-08 13:43:13 -0700241 } else {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800242 Context->ReportError(CE->getExprLoc(), "invalid vector cast");
Stephen Hinesdbb6dc32013-05-08 13:43:13 -0700243 }
244 mValid = false;
245 }
246 }
247 Visit(CE->getSubExpr());
248}
249
250
Stephen Hines11274a72012-09-26 19:14:20 -0700251void RSCheckAST::VisitExpr(clang::Expr *E) {
252 // This is where FS checks for code using pointer and/or 64-bit expressions
253 // (i.e. things like casts).
254
255 // First we skip implicit casts (things like function calls and explicit
256 // array accesses rely heavily on them and they are valid.
257 E = E->IgnoreImpCasts();
Stephen Hinese23d82b2015-06-11 17:00:04 -0700258
259 // Expressions at this point in the checker are not externally visible.
260 static const bool kIsExtern = false;
261
Stephen Hines11274a72012-09-26 19:14:20 -0700262 if (mIsFilterscript &&
Jean-Luc Brouilletc10bc752015-05-04 23:02:25 -0700263 !Slang::IsLocInRSHeaderFile(E->getExprLoc(), mSM) &&
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700264 !RSExportType::ValidateType(Context, C, E->getType(), nullptr, E->getExprLoc(),
Stephen Hinese23d82b2015-06-11 17:00:04 -0700265 mTargetAPI, mIsFilterscript, kIsExtern)) {
Stephen Hines11274a72012-09-26 19:14:20 -0700266 mValid = false;
267 } else {
268 // Only visit sub-expressions if we haven't already seen a violation.
269 VisitStmt(E);
270 }
271}
272
273
274bool RSCheckAST::Validate() {
275 clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
276 for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(),
277 DE = TUDecl->decls_end();
278 DI != DE;
279 DI++) {
Jean-Luc Brouilletc10bc752015-05-04 23:02:25 -0700280 if (!Slang::IsLocInRSHeaderFile(DI->getLocStart(), mSM)) {
Stephen Hines11274a72012-09-26 19:14:20 -0700281 if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*DI)) {
282 ValidateVarDecl(VD);
283 } else if (clang::FunctionDecl *FD =
284 llvm::dyn_cast<clang::FunctionDecl>(*DI)) {
285 ValidateFunctionDecl(FD);
286 } else if (clang::Stmt *Body = (*DI)->getBody()) {
287 Visit(Body);
288 }
289 }
290 }
291
292 return mValid;
293}
294
295} // namespace slang