Home | History | Annotate | Download | only in slang
      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_reduce.h"
     25 #include "slang_rs_export_type.h"
     26 
     27 namespace slang {
     28 
     29 void RSCheckAST::VisitStmt(clang::Stmt *S) {
     30   // This function does the actual iteration through all sub-Stmt's within
     31   // a given Stmt. Note that this function is skipped by all of the other
     32   // Visit* functions if we have already found a higher-level match.
     33   for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
     34        I != E;
     35        I++) {
     36     if (clang::Stmt *Child = *I) {
     37       Visit(Child);
     38     }
     39   }
     40 }
     41 
     42 void RSCheckAST::WarnOnSetElementAt(clang::CallExpr *E) {
     43   clang::FunctionDecl *Decl;
     44   Decl = clang::dyn_cast_or_null<clang::FunctionDecl>(E->getCalleeDecl());
     45 
     46   if (!Decl || Decl->getNameAsString() != std::string("rsSetElementAt")) {
     47     return;
     48   }
     49 
     50   clang::Expr *Expr;
     51   clang::ImplicitCastExpr *ImplCast;
     52   Expr = E->getArg(1);
     53   ImplCast = clang::dyn_cast_or_null<clang::ImplicitCastExpr>(Expr);
     54 
     55   if (!ImplCast) {
     56     return;
     57   }
     58 
     59   const clang::Type *Ty;
     60   const clang::VectorType *VectorTy;
     61   const clang::BuiltinType *ElementTy;
     62   Ty = ImplCast->getSubExpr()->getType()->getPointeeType()
     63     ->getUnqualifiedDesugaredType();
     64   VectorTy = clang::dyn_cast_or_null<clang::VectorType>(Ty);
     65 
     66   if (VectorTy) {
     67     ElementTy = clang::dyn_cast_or_null<clang::BuiltinType>(
     68       VectorTy->getElementType()->getUnqualifiedDesugaredType());
     69   } else {
     70     ElementTy = clang::dyn_cast_or_null<clang::BuiltinType>(
     71       Ty->getUnqualifiedDesugaredType());
     72   }
     73 
     74   if (!ElementTy) {
     75     return;
     76   }
     77 
     78   // We only support vectors with 2, 3 or 4 elements.
     79   if (VectorTy) {
     80     switch (VectorTy->getNumElements()) {
     81     default:
     82       return;
     83     case 2:
     84     case 3:
     85     case 4:
     86       break;
     87     }
     88   }
     89 
     90   const char *Name;
     91 
     92   switch (ElementTy->getKind()) {
     93     case clang::BuiltinType::Float:
     94       Name = "float";
     95       break;
     96     case clang::BuiltinType::Double:
     97       Name = "double";
     98       break;
     99     case clang::BuiltinType::Char_S:
    100       Name = "char";
    101       break;
    102     case clang::BuiltinType::Short:
    103       Name = "short";
    104       break;
    105     case clang::BuiltinType::Int:
    106       Name = "int";
    107       break;
    108     case clang::BuiltinType::Long:
    109       Name = "long";
    110       break;
    111     case clang::BuiltinType::UChar:
    112       Name = "uchar";
    113       break;
    114     case clang::BuiltinType::UShort:
    115       Name = "ushort";
    116       break;
    117     case clang::BuiltinType::UInt:
    118       Name = "uint";
    119       break;
    120     case clang::BuiltinType::ULong:
    121       Name = "ulong";
    122       break;
    123     default:
    124       return;
    125   }
    126 
    127   clang::DiagnosticBuilder DiagBuilder =
    128       Context->ReportWarning(E->getLocStart(),
    129                              "untyped rsSetElementAt() can reduce performance. "
    130                              "Use rsSetElementAt_%0%1() instead.");
    131   DiagBuilder << Name;
    132 
    133   if (VectorTy) {
    134     DiagBuilder << VectorTy->getNumElements();
    135   } else {
    136     DiagBuilder << "";
    137   }
    138 }
    139 
    140 void 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 
    149 void RSCheckAST::ValidateFunctionDecl(clang::FunctionDecl *FD) {
    150   if (!FD) {
    151     return;
    152   }
    153 
    154   if (FD->hasAttr<clang::KernelAttr>()) {
    155     // Validate that the kernel attribute is not used with static.
    156     if (FD->getStorageClass() == clang::SC_Static) {
    157       Context->ReportError(FD->getLocation(),
    158                            "Invalid use of attribute kernel with "
    159                            "static function declaration: %0")
    160         << FD->getName();
    161       mValid = false;
    162     }
    163 
    164     // We allow no arguments to the attribute, or an expected single
    165     // argument. If there is an expected single argument, we verify
    166     // that it is one of the recognized kernel kinds.
    167     llvm::StringRef KernelKind =
    168       FD->getAttr<clang::KernelAttr>()->getKernelKind();
    169 
    170     if (!KernelKind.empty()) {
    171       Context->ReportError(FD->getLocation(),
    172                            "Unknown kernel attribute argument '%0' "
    173                            "in declaration of function '%1'")
    174         << KernelKind << FD->getName();
    175       mValid = false;
    176     }
    177   }
    178 
    179   clang::QualType resultType = FD->getReturnType().getCanonicalType();
    180   bool isExtern = (FD->getFormalLinkage() == clang::ExternalLinkage);
    181 
    182   // We use FD as our NamedDecl in the case of a bad return type.
    183   if (!RSExportType::ValidateType(Context, C, resultType, FD,
    184                                   FD->getLocStart(), mTargetAPI,
    185                                   mIsFilterscript, isExtern)) {
    186     mValid = false;
    187   }
    188 
    189   size_t numParams = FD->getNumParams();
    190   for (size_t i = 0; i < numParams; i++) {
    191     clang::ParmVarDecl *PVD = FD->getParamDecl(i);
    192     clang::QualType QT = PVD->getType().getCanonicalType();
    193     if (!RSExportType::ValidateType(Context, C, QT, PVD, PVD->getLocStart(),
    194                                     mTargetAPI, mIsFilterscript, isExtern)) {
    195       mValid = false;
    196     }
    197   }
    198 
    199   bool saveKernel = mInKernel;
    200   mInKernel = RSExportForEach::isRSForEachFunc(mTargetAPI, FD);
    201 
    202   if (clang::Stmt *Body = FD->getBody()) {
    203     Visit(Body);
    204   }
    205 
    206   mInKernel = saveKernel;
    207 }
    208 
    209 
    210 void RSCheckAST::ValidateVarDecl(clang::VarDecl *VD) {
    211   if (!VD || RSContext::isSyntheticName(VD->getName())) {
    212     return;
    213   }
    214 
    215   clang::QualType QT = VD->getType();
    216 
    217   if (VD->getFormalLinkage() == clang::ExternalLinkage) {
    218     llvm::StringRef TypeName;
    219     const clang::Type *T = QT.getTypePtr();
    220     if (!RSExportType::NormalizeType(T, TypeName, Context, VD,
    221                                      NotLegacyKernelArgument)) {
    222       mValid = false;
    223     }
    224   }
    225 
    226   // We don't allow static (non-const) variables within kernels.
    227   if (mInKernel && VD->isStaticLocal()) {
    228     if (!QT.isConstQualified()) {
    229       Context->ReportError(
    230           VD->getLocation(),
    231           "Non-const static variables are not allowed in kernels: '%0'")
    232           << VD->getName();
    233       mValid = false;
    234     }
    235   }
    236 
    237   if (!RSExportType::ValidateVarDecl(Context, VD, mTargetAPI, mIsFilterscript)) {
    238     mValid = false;
    239   } else if (clang::Expr *Init = VD->getInit()) {
    240     // Only check the initializer if the decl is already ok.
    241     Visit(Init);
    242   }
    243 }
    244 
    245 
    246 void RSCheckAST::VisitDeclStmt(clang::DeclStmt *DS) {
    247   if (!Slang::IsLocInRSHeaderFile(DS->getLocStart(), mSM)) {
    248     for (clang::DeclStmt::decl_iterator I = DS->decl_begin(),
    249                                         E = DS->decl_end();
    250          I != E;
    251          ++I) {
    252       if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I)) {
    253         ValidateVarDecl(VD);
    254       } else if (clang::FunctionDecl *FD =
    255             llvm::dyn_cast<clang::FunctionDecl>(*I)) {
    256         ValidateFunctionDecl(FD);
    257       }
    258     }
    259   }
    260 }
    261 
    262 
    263 void RSCheckAST::VisitCastExpr(clang::CastExpr *CE) {
    264   if (CE->getCastKind() == clang::CK_BitCast) {
    265     clang::QualType QT = CE->getType();
    266     const clang::Type *T = QT.getTypePtr();
    267     if (T->isVectorType()) {
    268       if (llvm::isa<clang::ImplicitCastExpr>(CE)) {
    269         Context->ReportError(CE->getExprLoc(), "invalid implicit vector cast");
    270       } else {
    271         Context->ReportError(CE->getExprLoc(), "invalid vector cast");
    272       }
    273       mValid = false;
    274     }
    275   }
    276   Visit(CE->getSubExpr());
    277 }
    278 
    279 
    280 void RSCheckAST::VisitExpr(clang::Expr *E) {
    281   // This is where FS checks for code using pointer and/or 64-bit expressions
    282   // (i.e. things like casts).
    283 
    284   // First we skip implicit casts (things like function calls and explicit
    285   // array accesses rely heavily on them and they are valid.
    286   E = E->IgnoreImpCasts();
    287 
    288   // Expressions at this point in the checker are not externally visible.
    289   static const bool kIsExtern = false;
    290 
    291   if (mIsFilterscript &&
    292       !Slang::IsLocInRSHeaderFile(E->getExprLoc(), mSM) &&
    293       !RSExportType::ValidateType(Context, C, E->getType(), nullptr, E->getExprLoc(),
    294                                   mTargetAPI, mIsFilterscript, kIsExtern)) {
    295     mValid = false;
    296   } else {
    297     // Only visit sub-expressions if we haven't already seen a violation.
    298     VisitStmt(E);
    299   }
    300 }
    301 
    302 
    303 bool RSCheckAST::Validate() {
    304   clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
    305   for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(),
    306           DE = TUDecl->decls_end();
    307        DI != DE;
    308        DI++) {
    309     if (!Slang::IsLocInRSHeaderFile(DI->getLocStart(), mSM)) {
    310       if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*DI)) {
    311         ValidateVarDecl(VD);
    312       } else if (clang::FunctionDecl *FD =
    313             llvm::dyn_cast<clang::FunctionDecl>(*DI)) {
    314         ValidateFunctionDecl(FD);
    315       } else if (clang::Stmt *Body = (*DI)->getBody()) {
    316         Visit(Body);
    317       }
    318     }
    319   }
    320 
    321   return mValid;
    322 }
    323 
    324 }  // namespace slang
    325