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::ValidateFunctionDecl(clang::FunctionDecl *FD) {
     40   if (!FD) {
     41     return;
     42   }
     43 
     44   if (mIsFilterscript) {
     45     // Validate parameters for Filterscript.
     46     size_t numParams = FD->getNumParams();
     47 
     48     clang::QualType resultType = FD->getResultType().getCanonicalType();
     49 
     50     // We use FD as our NamedDecl in the case of a bad return type.
     51     if (!RSExportType::ValidateType(C, resultType, FD,
     52                                     FD->getLocStart(), mTargetAPI,
     53                                     mIsFilterscript)) {
     54       mValid = false;
     55     }
     56 
     57     for (size_t i = 0; i < numParams; i++) {
     58       clang::ParmVarDecl *PVD = FD->getParamDecl(i);
     59       clang::QualType QT = PVD->getType().getCanonicalType();
     60       if (!RSExportType::ValidateType(C, QT, PVD, PVD->getLocStart(),
     61                                       mTargetAPI, mIsFilterscript)) {
     62         mValid = false;
     63       }
     64     }
     65   }
     66 
     67   bool saveKernel = mInKernel;
     68   mInKernel = RSExportForEach::isRSForEachFunc(mTargetAPI, &mDiagEngine, FD);
     69 
     70   if (clang::Stmt *Body = FD->getBody()) {
     71     Visit(Body);
     72   }
     73 
     74   mInKernel = saveKernel;
     75 }
     76 
     77 
     78 void RSCheckAST::ValidateVarDecl(clang::VarDecl *VD) {
     79   if (!VD) {
     80     return;
     81   }
     82 
     83   clang::QualType QT = VD->getType();
     84 
     85   if (VD->getLinkage() == clang::ExternalLinkage) {
     86     llvm::StringRef TypeName;
     87     const clang::Type *T = QT.getTypePtr();
     88     if (!RSExportType::NormalizeType(T, TypeName, &mDiagEngine, VD)) {
     89       mValid = false;
     90     }
     91   }
     92 
     93   // We don't allow static (non-const) variables within kernels.
     94   if (mInKernel && VD->isStaticLocal()) {
     95     if (!QT.isConstQualified()) {
     96       mDiagEngine.Report(
     97         clang::FullSourceLoc(VD->getLocation(), mSM),
     98         mDiagEngine.getCustomDiagID(
     99           clang::DiagnosticsEngine::Error,
    100           "Non-const static variables are not allowed in kernels: '%0'"))
    101           << VD->getName();
    102       mValid = false;
    103     }
    104   }
    105 
    106   if (!RSExportType::ValidateVarDecl(VD, mTargetAPI, mIsFilterscript)) {
    107     mValid = false;
    108   } else if (clang::Expr *Init = VD->getInit()) {
    109     // Only check the initializer if the decl is already ok.
    110     Visit(Init);
    111   }
    112 }
    113 
    114 
    115 void RSCheckAST::VisitDeclStmt(clang::DeclStmt *DS) {
    116   if (!SlangRS::IsLocInRSHeaderFile(DS->getLocStart(), mSM)) {
    117     for (clang::DeclStmt::decl_iterator I = DS->decl_begin(),
    118                                         E = DS->decl_end();
    119          I != E;
    120          ++I) {
    121       if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I)) {
    122         ValidateVarDecl(VD);
    123       } else if (clang::FunctionDecl *FD =
    124             llvm::dyn_cast<clang::FunctionDecl>(*I)) {
    125         ValidateFunctionDecl(FD);
    126       }
    127     }
    128   }
    129 }
    130 
    131 
    132 void RSCheckAST::VisitExpr(clang::Expr *E) {
    133   // This is where FS checks for code using pointer and/or 64-bit expressions
    134   // (i.e. things like casts).
    135 
    136   // First we skip implicit casts (things like function calls and explicit
    137   // array accesses rely heavily on them and they are valid.
    138   E = E->IgnoreImpCasts();
    139   if (mIsFilterscript &&
    140       !SlangRS::IsLocInRSHeaderFile(E->getExprLoc(), mSM) &&
    141       !RSExportType::ValidateType(C, E->getType(), NULL, E->getExprLoc(),
    142                                   mTargetAPI, mIsFilterscript)) {
    143     mValid = false;
    144   } else {
    145     // Only visit sub-expressions if we haven't already seen a violation.
    146     VisitStmt(E);
    147   }
    148 }
    149 
    150 
    151 bool RSCheckAST::Validate() {
    152   clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
    153   for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(),
    154           DE = TUDecl->decls_end();
    155        DI != DE;
    156        DI++) {
    157     if (!SlangRS::IsLocInRSHeaderFile(DI->getLocStart(), mSM)) {
    158       if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*DI)) {
    159         ValidateVarDecl(VD);
    160       } else if (clang::FunctionDecl *FD =
    161             llvm::dyn_cast<clang::FunctionDecl>(*DI)) {
    162         ValidateFunctionDecl(FD);
    163       } else if (clang::Stmt *Body = (*DI)->getBody()) {
    164         Visit(Body);
    165       }
    166     }
    167   }
    168 
    169   return mValid;
    170 }
    171 
    172 }  // namespace slang
    173