slang_rs_check_ast.cpp revision 48d893dc7794b3cfb74f35955ca763ee4170f9ad
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 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 39void 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 = mDiagEngine.Report( 125 clang::FullSourceLoc(E->getLocStart(), mSM), 126 mDiagEngine.getCustomDiagID( clang::DiagnosticsEngine::Warning, 127 "untyped rsSetElementAt() can reduce performance. " 128 "Use rsSetElementAt_%0%1() instead.")); 129 DiagBuilder << Name; 130 131 if (VectorTy) { 132 DiagBuilder << VectorTy->getNumElements(); 133 } else { 134 DiagBuilder << ""; 135 } 136 137 return; 138} 139 140void RSCheckAST::VisitCallExpr(clang::CallExpr *E) { 141 WarnOnSetElementAt(E); 142 143 for (clang::CallExpr::arg_iterator AI = E->arg_begin(), AE = E->arg_end(); 144 AI != AE; ++AI) { 145 Visit(*AI); 146 } 147} 148 149void RSCheckAST::ValidateFunctionDecl(clang::FunctionDecl *FD) { 150 if (!FD) { 151 return; 152 } 153 154 if (mIsFilterscript) { 155 // Validate parameters for Filterscript. 156 size_t numParams = FD->getNumParams(); 157 158 clang::QualType resultType = FD->getResultType().getCanonicalType(); 159 160 // We use FD as our NamedDecl in the case of a bad return type. 161 if (!RSExportType::ValidateType(C, resultType, FD, 162 FD->getLocStart(), mTargetAPI, 163 mIsFilterscript)) { 164 mValid = false; 165 } 166 167 for (size_t i = 0; i < numParams; i++) { 168 clang::ParmVarDecl *PVD = FD->getParamDecl(i); 169 clang::QualType QT = PVD->getType().getCanonicalType(); 170 if (!RSExportType::ValidateType(C, QT, PVD, PVD->getLocStart(), 171 mTargetAPI, mIsFilterscript)) { 172 mValid = false; 173 } 174 } 175 } 176 177 bool saveKernel = mInKernel; 178 mInKernel = RSExportForEach::isRSForEachFunc(mTargetAPI, &mDiagEngine, FD); 179 180 if (clang::Stmt *Body = FD->getBody()) { 181 Visit(Body); 182 } 183 184 mInKernel = saveKernel; 185} 186 187 188void RSCheckAST::ValidateVarDecl(clang::VarDecl *VD) { 189 if (!VD) { 190 return; 191 } 192 193 clang::QualType QT = VD->getType(); 194 195 if (VD->getFormalLinkage() == clang::ExternalLinkage) { 196 llvm::StringRef TypeName; 197 const clang::Type *T = QT.getTypePtr(); 198 if (!RSExportType::NormalizeType(T, TypeName, Context, VD)) { 199 mValid = false; 200 } 201 } 202 203 // We don't allow static (non-const) variables within kernels. 204 if (mInKernel && VD->isStaticLocal()) { 205 if (!QT.isConstQualified()) { 206 mDiagEngine.Report( 207 clang::FullSourceLoc(VD->getLocation(), mSM), 208 mDiagEngine.getCustomDiagID( 209 clang::DiagnosticsEngine::Error, 210 "Non-const static variables are not allowed in kernels: '%0'")) 211 << VD->getName(); 212 mValid = false; 213 } 214 } 215 216 if (!RSExportType::ValidateVarDecl(VD, mTargetAPI, mIsFilterscript)) { 217 mValid = false; 218 } else if (clang::Expr *Init = VD->getInit()) { 219 // Only check the initializer if the decl is already ok. 220 Visit(Init); 221 } 222} 223 224 225void RSCheckAST::VisitDeclStmt(clang::DeclStmt *DS) { 226 if (!SlangRS::IsLocInRSHeaderFile(DS->getLocStart(), mSM)) { 227 for (clang::DeclStmt::decl_iterator I = DS->decl_begin(), 228 E = DS->decl_end(); 229 I != E; 230 ++I) { 231 if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I)) { 232 ValidateVarDecl(VD); 233 } else if (clang::FunctionDecl *FD = 234 llvm::dyn_cast<clang::FunctionDecl>(*I)) { 235 ValidateFunctionDecl(FD); 236 } 237 } 238 } 239} 240 241 242void RSCheckAST::VisitCastExpr(clang::CastExpr *CE) { 243 if (CE->getCastKind() == clang::CK_BitCast) { 244 clang::QualType QT = CE->getType(); 245 const clang::Type *T = QT.getTypePtr(); 246 if (T->isVectorType()) { 247 if (llvm::isa<clang::ImplicitCastExpr>(CE)) { 248 mDiagEngine.Report( 249 clang::FullSourceLoc(CE->getExprLoc(), 250 mDiagEngine.getSourceManager()), 251 mDiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error, 252 "invalid implicit vector cast")); 253 } else { 254 mDiagEngine.Report( 255 clang::FullSourceLoc(CE->getExprLoc(), 256 mDiagEngine.getSourceManager()), 257 mDiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error, 258 "invalid vector cast")); 259 } 260 mValid = false; 261 } 262 } 263 Visit(CE->getSubExpr()); 264} 265 266 267void RSCheckAST::VisitExpr(clang::Expr *E) { 268 // This is where FS checks for code using pointer and/or 64-bit expressions 269 // (i.e. things like casts). 270 271 // First we skip implicit casts (things like function calls and explicit 272 // array accesses rely heavily on them and they are valid. 273 E = E->IgnoreImpCasts(); 274 if (mIsFilterscript && 275 !SlangRS::IsLocInRSHeaderFile(E->getExprLoc(), mSM) && 276 !RSExportType::ValidateType(C, E->getType(), NULL, E->getExprLoc(), 277 mTargetAPI, mIsFilterscript)) { 278 mValid = false; 279 } else { 280 // Only visit sub-expressions if we haven't already seen a violation. 281 VisitStmt(E); 282 } 283} 284 285 286bool RSCheckAST::Validate() { 287 clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl(); 288 for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(), 289 DE = TUDecl->decls_end(); 290 DI != DE; 291 DI++) { 292 if (!SlangRS::IsLocInRSHeaderFile(DI->getLocStart(), mSM)) { 293 if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*DI)) { 294 ValidateVarDecl(VD); 295 } else if (clang::FunctionDecl *FD = 296 llvm::dyn_cast<clang::FunctionDecl>(*DI)) { 297 ValidateFunctionDecl(FD); 298 } else if (clang::Stmt *Body = (*DI)->getBody()) { 299 Visit(Body); 300 } 301 } 302 } 303 304 return mValid; 305} 306 307} // namespace slang 308