slang_rs_check_ast.cpp revision f5b882cc561f656eb650d0fa6db7bac57989ab12
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 "clang/AST/Attr.h" 18 19#include "slang_rs_check_ast.h" 20 21#include "slang_assert.h" 22#include "slang.h" 23#include "slang_rs_export_foreach.h" 24#include "slang_rs_export_type.h" 25 26namespace slang { 27 28void RSCheckAST::VisitStmt(clang::Stmt *S) { 29 // This function does the actual iteration through all sub-Stmt's within 30 // a given Stmt. Note that this function is skipped by all of the other 31 // Visit* functions if we have already found a higher-level match. 32 for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end(); 33 I != E; 34 I++) { 35 if (clang::Stmt *Child = *I) { 36 Visit(Child); 37 } 38 } 39} 40 41void RSCheckAST::WarnOnSetElementAt(clang::CallExpr *E) { 42 clang::FunctionDecl *Decl; 43 Decl = clang::dyn_cast_or_null<clang::FunctionDecl>(E->getCalleeDecl()); 44 45 if (!Decl || Decl->getNameAsString() != std::string("rsSetElementAt")) { 46 return; 47 } 48 49 clang::Expr *Expr; 50 clang::ImplicitCastExpr *ImplCast; 51 Expr = E->getArg(1); 52 ImplCast = clang::dyn_cast_or_null<clang::ImplicitCastExpr>(Expr); 53 54 if (!ImplCast) { 55 return; 56 } 57 58 const clang::Type *Ty; 59 const clang::VectorType *VectorTy; 60 const clang::BuiltinType *ElementTy; 61 Ty = ImplCast->getSubExpr()->getType()->getPointeeType() 62 ->getUnqualifiedDesugaredType(); 63 VectorTy = clang::dyn_cast_or_null<clang::VectorType>(Ty); 64 65 if (VectorTy) { 66 ElementTy = clang::dyn_cast_or_null<clang::BuiltinType>( 67 VectorTy->getElementType()->getUnqualifiedDesugaredType()); 68 } else { 69 ElementTy = clang::dyn_cast_or_null<clang::BuiltinType>( 70 Ty->getUnqualifiedDesugaredType()); 71 } 72 73 if (!ElementTy) { 74 return; 75 } 76 77 // We only support vectors with 2, 3 or 4 elements. 78 if (VectorTy) { 79 switch (VectorTy->getNumElements()) { 80 default: 81 return; 82 case 2: 83 case 3: 84 case 4: 85 break; 86 } 87 } 88 89 const char *Name; 90 91 switch (ElementTy->getKind()) { 92 case clang::BuiltinType::Float: 93 Name = "float"; 94 break; 95 case clang::BuiltinType::Double: 96 Name = "double"; 97 break; 98 case clang::BuiltinType::Char_S: 99 Name = "char"; 100 break; 101 case clang::BuiltinType::Short: 102 Name = "short"; 103 break; 104 case clang::BuiltinType::Int: 105 Name = "int"; 106 break; 107 case clang::BuiltinType::Long: 108 Name = "long"; 109 break; 110 case clang::BuiltinType::UChar: 111 Name = "uchar"; 112 break; 113 case clang::BuiltinType::UShort: 114 Name = "ushort"; 115 break; 116 case clang::BuiltinType::UInt: 117 Name = "uint"; 118 break; 119 case clang::BuiltinType::ULong: 120 Name = "ulong"; 121 break; 122 default: 123 return; 124 } 125 126 clang::DiagnosticBuilder DiagBuilder = 127 Context->ReportWarning(E->getLocStart(), 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 139void RSCheckAST::VisitCallExpr(clang::CallExpr *E) { 140 WarnOnSetElementAt(E); 141 142 for (clang::CallExpr::arg_iterator AI = E->arg_begin(), AE = E->arg_end(); 143 AI != AE; ++AI) { 144 Visit(*AI); 145 } 146} 147 148void RSCheckAST::ValidateFunctionDecl(clang::FunctionDecl *FD) { 149 if (!FD) { 150 return; 151 } 152 153 // Validate that the kernel attribute is not used with static. 154 if (FD->hasAttr<clang::KernelAttr>() && 155 FD->getStorageClass() == clang::SC_Static) { 156 Context->ReportError(FD->getLocation(), 157 "Invalid use of attribute kernel with " 158 "static function declaration: %0") 159 << FD->getName(); 160 mValid = false; 161 } 162 163 clang::QualType resultType = FD->getReturnType().getCanonicalType(); 164 bool isExtern = (FD->getFormalLinkage() == clang::ExternalLinkage); 165 166 // We use FD as our NamedDecl in the case of a bad return type. 167 if (!RSExportType::ValidateType(Context, C, resultType, FD, 168 FD->getLocStart(), mTargetAPI, 169 mIsFilterscript, isExtern)) { 170 mValid = false; 171 } 172 173 size_t numParams = FD->getNumParams(); 174 for (size_t i = 0; i < numParams; i++) { 175 clang::ParmVarDecl *PVD = FD->getParamDecl(i); 176 clang::QualType QT = PVD->getType().getCanonicalType(); 177 if (!RSExportType::ValidateType(Context, C, QT, PVD, PVD->getLocStart(), 178 mTargetAPI, mIsFilterscript, isExtern)) { 179 mValid = false; 180 } 181 } 182 183 bool saveKernel = mInKernel; 184 mInKernel = RSExportForEach::isRSForEachFunc(mTargetAPI, FD); 185 186 if (clang::Stmt *Body = FD->getBody()) { 187 Visit(Body); 188 } 189 190 mInKernel = saveKernel; 191} 192 193 194void RSCheckAST::ValidateVarDecl(clang::VarDecl *VD) { 195 if (!VD) { 196 return; 197 } 198 199 clang::QualType QT = VD->getType(); 200 201 if (VD->getFormalLinkage() == clang::ExternalLinkage) { 202 llvm::StringRef TypeName; 203 const clang::Type *T = QT.getTypePtr(); 204 if (!RSExportType::NormalizeType(T, TypeName, Context, VD)) { 205 mValid = false; 206 } 207 } 208 209 // We don't allow static (non-const) variables within kernels. 210 if (mInKernel && VD->isStaticLocal()) { 211 if (!QT.isConstQualified()) { 212 Context->ReportError( 213 VD->getLocation(), 214 "Non-const static variables are not allowed in kernels: '%0'") 215 << VD->getName(); 216 mValid = false; 217 } 218 } 219 220 if (!RSExportType::ValidateVarDecl(Context, VD, mTargetAPI, mIsFilterscript)) { 221 mValid = false; 222 } else if (clang::Expr *Init = VD->getInit()) { 223 // Only check the initializer if the decl is already ok. 224 Visit(Init); 225 } 226} 227 228 229void RSCheckAST::VisitDeclStmt(clang::DeclStmt *DS) { 230 if (!Slang::IsLocInRSHeaderFile(DS->getLocStart(), mSM)) { 231 for (clang::DeclStmt::decl_iterator I = DS->decl_begin(), 232 E = DS->decl_end(); 233 I != E; 234 ++I) { 235 if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I)) { 236 ValidateVarDecl(VD); 237 } else if (clang::FunctionDecl *FD = 238 llvm::dyn_cast<clang::FunctionDecl>(*I)) { 239 ValidateFunctionDecl(FD); 240 } 241 } 242 } 243} 244 245 246void RSCheckAST::VisitCastExpr(clang::CastExpr *CE) { 247 if (CE->getCastKind() == clang::CK_BitCast) { 248 clang::QualType QT = CE->getType(); 249 const clang::Type *T = QT.getTypePtr(); 250 if (T->isVectorType()) { 251 if (llvm::isa<clang::ImplicitCastExpr>(CE)) { 252 Context->ReportError(CE->getExprLoc(), "invalid implicit vector cast"); 253 } else { 254 Context->ReportError(CE->getExprLoc(), "invalid vector cast"); 255 } 256 mValid = false; 257 } 258 } 259 Visit(CE->getSubExpr()); 260} 261 262 263void RSCheckAST::VisitExpr(clang::Expr *E) { 264 // This is where FS checks for code using pointer and/or 64-bit expressions 265 // (i.e. things like casts). 266 267 // First we skip implicit casts (things like function calls and explicit 268 // array accesses rely heavily on them and they are valid. 269 E = E->IgnoreImpCasts(); 270 271 // Expressions at this point in the checker are not externally visible. 272 static const bool kIsExtern = false; 273 274 if (mIsFilterscript && 275 !Slang::IsLocInRSHeaderFile(E->getExprLoc(), mSM) && 276 !RSExportType::ValidateType(Context, C, E->getType(), nullptr, E->getExprLoc(), 277 mTargetAPI, mIsFilterscript, kIsExtern)) { 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 (!Slang::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