• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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"
21 #include "slang_rs_export_foreach.h"
22 #include "slang_rs_export_type.h"
23 
24 namespace slang {
25 
VisitStmt(clang::Stmt * S)26 void 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 
WarnOnSetElementAt(clang::CallExpr * E)39 void RSCheckAST::WarnOnSetElementAt(clang::CallExpr *E) {
40   clang::FunctionDecl *Decl;
41   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 
124   clang::DiagnosticBuilder DiagBuilder =
125       Context->ReportWarning(E->getLocStart(),
126                              "untyped rsSetElementAt() can reduce performance. "
127                              "Use rsSetElementAt_%0%1() instead.");
128   DiagBuilder << Name;
129 
130   if (VectorTy) {
131     DiagBuilder << VectorTy->getNumElements();
132   } else {
133     DiagBuilder << "";
134   }
135 }
136 
VisitCallExpr(clang::CallExpr * E)137 void 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 
ValidateFunctionDecl(clang::FunctionDecl * FD)146 void RSCheckAST::ValidateFunctionDecl(clang::FunctionDecl *FD) {
147   if (!FD) {
148     return;
149   }
150 
151   if (mIsFilterscript) {
152     // Validate parameters for Filterscript.
153     size_t numParams = FD->getNumParams();
154 
155     clang::QualType resultType = FD->getReturnType().getCanonicalType();
156 
157     // We use FD as our NamedDecl in the case of a bad return type.
158     if (!RSExportType::ValidateType(Context, C, resultType, FD,
159                                     FD->getLocStart(), mTargetAPI,
160                                     mIsFilterscript)) {
161       mValid = false;
162     }
163 
164     for (size_t i = 0; i < numParams; i++) {
165       clang::ParmVarDecl *PVD = FD->getParamDecl(i);
166       clang::QualType QT = PVD->getType().getCanonicalType();
167       if (!RSExportType::ValidateType(Context, C, QT, PVD, PVD->getLocStart(),
168                                       mTargetAPI, mIsFilterscript)) {
169         mValid = false;
170       }
171     }
172   }
173 
174   bool saveKernel = mInKernel;
175   mInKernel = RSExportForEach::isRSForEachFunc(mTargetAPI, Context, FD);
176 
177   if (clang::Stmt *Body = FD->getBody()) {
178     Visit(Body);
179   }
180 
181   mInKernel = saveKernel;
182 }
183 
184 
ValidateVarDecl(clang::VarDecl * VD)185 void RSCheckAST::ValidateVarDecl(clang::VarDecl *VD) {
186   if (!VD) {
187     return;
188   }
189 
190   clang::QualType QT = VD->getType();
191 
192   if (VD->getFormalLinkage() == clang::ExternalLinkage) {
193     llvm::StringRef TypeName;
194     const clang::Type *T = QT.getTypePtr();
195     if (!RSExportType::NormalizeType(T, TypeName, Context, VD)) {
196       mValid = false;
197     }
198   }
199 
200   // We don't allow static (non-const) variables within kernels.
201   if (mInKernel && VD->isStaticLocal()) {
202     if (!QT.isConstQualified()) {
203       Context->ReportError(
204           VD->getLocation(),
205           "Non-const static variables are not allowed in kernels: '%0'")
206           << VD->getName();
207       mValid = false;
208     }
209   }
210 
211   if (!RSExportType::ValidateVarDecl(Context, VD, mTargetAPI, mIsFilterscript)) {
212     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 
VisitDeclStmt(clang::DeclStmt * DS)220 void 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 
VisitCastExpr(clang::CastExpr * CE)237 void 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()) {
242       if (llvm::isa<clang::ImplicitCastExpr>(CE)) {
243         Context->ReportError(CE->getExprLoc(), "invalid implicit vector cast");
244       } else {
245         Context->ReportError(CE->getExprLoc(), "invalid vector cast");
246       }
247       mValid = false;
248     }
249   }
250   Visit(CE->getSubExpr());
251 }
252 
253 
VisitExpr(clang::Expr * E)254 void 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) &&
263       !RSExportType::ValidateType(Context, C, E->getType(), NULL, E->getExprLoc(),
264                                   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 
Validate()273 bool 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
295