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.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   clang::QualType resultType = FD->getReturnType().getCanonicalType();
152   bool isExtern = (FD->getFormalLinkage() == clang::ExternalLinkage);
153 
154   // 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   }
160 
161   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)) {
167       mValid = false;
168     }
169   }
170 
171   bool saveKernel = mInKernel;
172   mInKernel = RSExportForEach::isRSForEachFunc(mTargetAPI, Context, FD);
173 
174   if (clang::Stmt *Body = FD->getBody()) {
175     Visit(Body);
176   }
177 
178   mInKernel = saveKernel;
179 }
180 
181 
ValidateVarDecl(clang::VarDecl * VD)182 void RSCheckAST::ValidateVarDecl(clang::VarDecl *VD) {
183   if (!VD) {
184     return;
185   }
186 
187   clang::QualType QT = VD->getType();
188 
189   if (VD->getFormalLinkage() == clang::ExternalLinkage) {
190     llvm::StringRef TypeName;
191     const clang::Type *T = QT.getTypePtr();
192     if (!RSExportType::NormalizeType(T, TypeName, Context, VD)) {
193       mValid = false;
194     }
195   }
196 
197   // We don't allow static (non-const) variables within kernels.
198   if (mInKernel && VD->isStaticLocal()) {
199     if (!QT.isConstQualified()) {
200       Context->ReportError(
201           VD->getLocation(),
202           "Non-const static variables are not allowed in kernels: '%0'")
203           << VD->getName();
204       mValid = false;
205     }
206   }
207 
208   if (!RSExportType::ValidateVarDecl(Context, VD, mTargetAPI, mIsFilterscript)) {
209     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 
VisitDeclStmt(clang::DeclStmt * DS)217 void RSCheckAST::VisitDeclStmt(clang::DeclStmt *DS) {
218   if (!Slang::IsLocInRSHeaderFile(DS->getLocStart(), mSM)) {
219     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 
VisitCastExpr(clang::CastExpr * CE)234 void 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()) {
239       if (llvm::isa<clang::ImplicitCastExpr>(CE)) {
240         Context->ReportError(CE->getExprLoc(), "invalid implicit vector cast");
241       } else {
242         Context->ReportError(CE->getExprLoc(), "invalid vector cast");
243       }
244       mValid = false;
245     }
246   }
247   Visit(CE->getSubExpr());
248 }
249 
250 
VisitExpr(clang::Expr * E)251 void 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();
258 
259   // Expressions at this point in the checker are not externally visible.
260   static const bool kIsExtern = false;
261 
262   if (mIsFilterscript &&
263       !Slang::IsLocInRSHeaderFile(E->getExprLoc(), mSM) &&
264       !RSExportType::ValidateType(Context, C, E->getType(), nullptr, E->getExprLoc(),
265                                   mTargetAPI, mIsFilterscript, kIsExtern)) {
266     mValid = false;
267   } else {
268     // Only visit sub-expressions if we haven't already seen a violation.
269     VisitStmt(E);
270   }
271 }
272 
273 
Validate()274 bool 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++) {
280     if (!Slang::IsLocInRSHeaderFile(DI->getLocStart(), mSM)) {
281       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
296