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