• 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   clang::DiagnosticsEngine &DiagEngine = C.getDiagnostics();
42   Decl = clang::dyn_cast_or_null<clang::FunctionDecl>(E->getCalleeDecl());
43 
44   if (!Decl || Decl->getNameAsString() != std::string("rsSetElementAt")) {
45     return;
46   }
47 
48   clang::Expr *Expr;
49   clang::ImplicitCastExpr *ImplCast;
50   Expr = E->getArg(1);
51   ImplCast = clang::dyn_cast_or_null<clang::ImplicitCastExpr>(Expr);
52 
53   if (!ImplCast) {
54     return;
55   }
56 
57   const clang::Type *Ty;
58   const clang::VectorType *VectorTy;
59   const clang::BuiltinType *ElementTy;
60   Ty = ImplCast->getSubExpr()->getType()->getPointeeType()
61     ->getUnqualifiedDesugaredType();
62   VectorTy = clang::dyn_cast_or_null<clang::VectorType>(Ty);
63 
64   if (VectorTy) {
65     ElementTy = clang::dyn_cast_or_null<clang::BuiltinType>(
66       VectorTy->getElementType()->getUnqualifiedDesugaredType());
67   } else {
68     ElementTy = clang::dyn_cast_or_null<clang::BuiltinType>(
69       Ty->getUnqualifiedDesugaredType());
70   }
71 
72   if (!ElementTy) {
73     return;
74   }
75 
76   // We only support vectors with 2, 3 or 4 elements.
77   if (VectorTy) {
78     switch (VectorTy->getNumElements()) {
79     default:
80       return;
81     case 2:
82     case 3:
83     case 4:
84       break;
85     }
86   }
87 
88   const char *Name;
89 
90   switch (ElementTy->getKind()) {
91     case clang::BuiltinType::Float:
92       Name = "float";
93       break;
94     case clang::BuiltinType::Double:
95       Name = "double";
96       break;
97     case clang::BuiltinType::Char_S:
98       Name = "char";
99       break;
100     case clang::BuiltinType::Short:
101       Name = "short";
102       break;
103     case clang::BuiltinType::Int:
104       Name = "int";
105       break;
106     case clang::BuiltinType::Long:
107       Name = "long";
108       break;
109     case clang::BuiltinType::UChar:
110       Name = "uchar";
111       break;
112     case clang::BuiltinType::UShort:
113       Name = "ushort";
114       break;
115     case clang::BuiltinType::UInt:
116       Name = "uint";
117       break;
118     case clang::BuiltinType::ULong:
119       Name = "ulong";
120       break;
121     default:
122       return;
123   }
124 
125   clang::DiagnosticBuilder DiagBuilder =  DiagEngine.Report(
126     clang::FullSourceLoc(E->getLocStart(), mSM),
127     mDiagEngine.getCustomDiagID( clang::DiagnosticsEngine::Warning,
128     "untyped rsSetElementAt() can reduce performance. "
129     "Use rsSetElementAt_%0%1() instead."));
130   DiagBuilder << Name;
131 
132   if (VectorTy) {
133     DiagBuilder << VectorTy->getNumElements();
134   } else {
135     DiagBuilder << "";
136   }
137 
138   return;
139 }
140 
VisitCallExpr(clang::CallExpr * E)141 void RSCheckAST::VisitCallExpr(clang::CallExpr *E) {
142   WarnOnSetElementAt(E);
143 
144   for (clang::CallExpr::arg_iterator AI = E->arg_begin(), AE = E->arg_end();
145        AI != AE; ++AI) {
146     Visit(*AI);
147   }
148 }
149 
ValidateFunctionDecl(clang::FunctionDecl * FD)150 void RSCheckAST::ValidateFunctionDecl(clang::FunctionDecl *FD) {
151   if (!FD) {
152     return;
153   }
154 
155   if (mIsFilterscript) {
156     // Validate parameters for Filterscript.
157     size_t numParams = FD->getNumParams();
158 
159     clang::QualType resultType = FD->getResultType().getCanonicalType();
160 
161     // We use FD as our NamedDecl in the case of a bad return type.
162     if (!RSExportType::ValidateType(C, resultType, FD,
163                                     FD->getLocStart(), mTargetAPI,
164                                     mIsFilterscript)) {
165       mValid = false;
166     }
167 
168     for (size_t i = 0; i < numParams; i++) {
169       clang::ParmVarDecl *PVD = FD->getParamDecl(i);
170       clang::QualType QT = PVD->getType().getCanonicalType();
171       if (!RSExportType::ValidateType(C, QT, PVD, PVD->getLocStart(),
172                                       mTargetAPI, mIsFilterscript)) {
173         mValid = false;
174       }
175     }
176   }
177 
178   bool saveKernel = mInKernel;
179   mInKernel = RSExportForEach::isRSForEachFunc(mTargetAPI, &mDiagEngine, FD);
180 
181   if (clang::Stmt *Body = FD->getBody()) {
182     Visit(Body);
183   }
184 
185   mInKernel = saveKernel;
186 }
187 
188 
ValidateVarDecl(clang::VarDecl * VD)189 void RSCheckAST::ValidateVarDecl(clang::VarDecl *VD) {
190   if (!VD) {
191     return;
192   }
193 
194   clang::QualType QT = VD->getType();
195 
196   if (VD->getFormalLinkage() == clang::ExternalLinkage) {
197     llvm::StringRef TypeName;
198     const clang::Type *T = QT.getTypePtr();
199     if (!RSExportType::NormalizeType(T, TypeName, &mDiagEngine, VD)) {
200       mValid = false;
201     }
202   }
203 
204   // We don't allow static (non-const) variables within kernels.
205   if (mInKernel && VD->isStaticLocal()) {
206     if (!QT.isConstQualified()) {
207       mDiagEngine.Report(
208         clang::FullSourceLoc(VD->getLocation(), mSM),
209         mDiagEngine.getCustomDiagID(
210           clang::DiagnosticsEngine::Error,
211           "Non-const static variables are not allowed in kernels: '%0'"))
212           << VD->getName();
213       mValid = false;
214     }
215   }
216 
217   if (!RSExportType::ValidateVarDecl(VD, mTargetAPI, mIsFilterscript)) {
218     mValid = false;
219   } else if (clang::Expr *Init = VD->getInit()) {
220     // Only check the initializer if the decl is already ok.
221     Visit(Init);
222   }
223 }
224 
225 
VisitDeclStmt(clang::DeclStmt * DS)226 void RSCheckAST::VisitDeclStmt(clang::DeclStmt *DS) {
227   if (!SlangRS::IsLocInRSHeaderFile(DS->getLocStart(), mSM)) {
228     for (clang::DeclStmt::decl_iterator I = DS->decl_begin(),
229                                         E = DS->decl_end();
230          I != E;
231          ++I) {
232       if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I)) {
233         ValidateVarDecl(VD);
234       } else if (clang::FunctionDecl *FD =
235             llvm::dyn_cast<clang::FunctionDecl>(*I)) {
236         ValidateFunctionDecl(FD);
237       }
238     }
239   }
240 }
241 
242 
VisitCastExpr(clang::CastExpr * CE)243 void RSCheckAST::VisitCastExpr(clang::CastExpr *CE) {
244   if (CE->getCastKind() == clang::CK_BitCast) {
245     clang::QualType QT = CE->getType();
246     const clang::Type *T = QT.getTypePtr();
247     if (T->isVectorType()) {
248       clang::DiagnosticsEngine &DiagEngine = C.getDiagnostics();
249       if (llvm::isa<clang::ImplicitCastExpr>(CE)) {
250         DiagEngine.Report(
251           clang::FullSourceLoc(CE->getExprLoc(),
252                                DiagEngine.getSourceManager()),
253           DiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
254                                      "invalid implicit vector cast"));
255       } else {
256         DiagEngine.Report(
257           clang::FullSourceLoc(CE->getExprLoc(),
258                                DiagEngine.getSourceManager()),
259           DiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
260                                      "invalid vector cast"));
261       }
262       mValid = false;
263     }
264   }
265   Visit(CE->getSubExpr());
266 }
267 
268 
VisitExpr(clang::Expr * E)269 void RSCheckAST::VisitExpr(clang::Expr *E) {
270   // This is where FS checks for code using pointer and/or 64-bit expressions
271   // (i.e. things like casts).
272 
273   // First we skip implicit casts (things like function calls and explicit
274   // array accesses rely heavily on them and they are valid.
275   E = E->IgnoreImpCasts();
276   if (mIsFilterscript &&
277       !SlangRS::IsLocInRSHeaderFile(E->getExprLoc(), mSM) &&
278       !RSExportType::ValidateType(C, E->getType(), NULL, E->getExprLoc(),
279                                   mTargetAPI, mIsFilterscript)) {
280     mValid = false;
281   } else {
282     // Only visit sub-expressions if we haven't already seen a violation.
283     VisitStmt(E);
284   }
285 }
286 
287 
Validate()288 bool RSCheckAST::Validate() {
289   clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
290   for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(),
291           DE = TUDecl->decls_end();
292        DI != DE;
293        DI++) {
294     if (!SlangRS::IsLocInRSHeaderFile(DI->getLocStart(), mSM)) {
295       if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*DI)) {
296         ValidateVarDecl(VD);
297       } else if (clang::FunctionDecl *FD =
298             llvm::dyn_cast<clang::FunctionDecl>(*DI)) {
299         ValidateFunctionDecl(FD);
300       } else if (clang::Stmt *Body = (*DI)->getBody()) {
301         Visit(Body);
302       }
303     }
304   }
305 
306   return mValid;
307 }
308 
309 }  // namespace slang
310