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_type.h"
     22 
     23 namespace slang {
     24 
     25 void RSCheckAST::VisitStmt(clang::Stmt *S) {
     26   // This function does the actual iteration through all sub-Stmt's within
     27   // a given Stmt. Note that this function is skipped by all of the other
     28   // Visit* functions if we have already found a higher-level match.
     29   for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
     30        I != E;
     31        I++) {
     32     if (clang::Stmt *Child = *I) {
     33       Visit(Child);
     34     }
     35   }
     36 }
     37 
     38 void RSCheckAST::ValidateFunctionDecl(clang::FunctionDecl *FD) {
     39   if (!FD) {
     40     return;
     41   }
     42 
     43   if (!mIsFilterscript) {
     44     // No additional validation for non-Filterscript functions.
     45     if (clang::Stmt *Body = FD->getBody()) {
     46       Visit(Body);
     47     }
     48     return;
     49   }
     50 
     51   size_t numParams = FD->getNumParams();
     52 
     53   clang::QualType resultType = FD->getResultType().getCanonicalType();
     54 
     55   // We use FD as our NamedDecl in the case of a bad return type.
     56   if (!RSExportType::ValidateType(C, resultType, FD,
     57                                   FD->getLocStart(), mTargetAPI,
     58                                   mIsFilterscript)) {
     59     mValid = false;
     60   }
     61 
     62   for (size_t i = 0; i < numParams; i++) {
     63     clang::ParmVarDecl *PVD = FD->getParamDecl(i);
     64     clang::QualType QT = PVD->getType().getCanonicalType();
     65     if (!RSExportType::ValidateType(C, QT, PVD, PVD->getLocStart(),
     66                                     mTargetAPI, mIsFilterscript)) {
     67       mValid = false;
     68     }
     69   }
     70 
     71   if (clang::Stmt *Body = FD->getBody()) {
     72     Visit(Body);
     73   }
     74 }
     75 
     76 
     77 void RSCheckAST::ValidateVarDecl(clang::VarDecl *VD) {
     78   if (!VD) {
     79     return;
     80   }
     81 
     82   const clang::Type *T = VD->getType().getTypePtr();
     83 
     84   if (VD->getLinkage() == clang::ExternalLinkage) {
     85     llvm::StringRef TypeName;
     86     if (!RSExportType::NormalizeType(T, TypeName, &mDiagEngine, VD)) {
     87       mValid = false;
     88     }
     89   }
     90 
     91   if (!RSExportType::ValidateVarDecl(VD, mTargetAPI, mIsFilterscript)) {
     92     mValid = false;
     93   } else if (clang::Expr *Init = VD->getInit()) {
     94     // Only check the initializer if the decl is already ok.
     95     Visit(Init);
     96   }
     97 }
     98 
     99 
    100 void RSCheckAST::VisitDeclStmt(clang::DeclStmt *DS) {
    101   if (!SlangRS::IsLocInRSHeaderFile(DS->getLocStart(), mSM)) {
    102     for (clang::DeclStmt::decl_iterator I = DS->decl_begin(),
    103                                         E = DS->decl_end();
    104          I != E;
    105          ++I) {
    106       if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I)) {
    107         ValidateVarDecl(VD);
    108       } else if (clang::FunctionDecl *FD =
    109             llvm::dyn_cast<clang::FunctionDecl>(*I)) {
    110         ValidateFunctionDecl(FD);
    111       }
    112     }
    113   }
    114 }
    115 
    116 
    117 void RSCheckAST::VisitExpr(clang::Expr *E) {
    118   // This is where FS checks for code using pointer and/or 64-bit expressions
    119   // (i.e. things like casts).
    120 
    121   // First we skip implicit casts (things like function calls and explicit
    122   // array accesses rely heavily on them and they are valid.
    123   E = E->IgnoreImpCasts();
    124   if (mIsFilterscript &&
    125       !SlangRS::IsLocInRSHeaderFile(E->getExprLoc(), mSM) &&
    126       !RSExportType::ValidateType(C, E->getType(), NULL, E->getExprLoc(),
    127                                   mTargetAPI, mIsFilterscript)) {
    128     mValid = false;
    129   } else {
    130     // Only visit sub-expressions if we haven't already seen a violation.
    131     VisitStmt(E);
    132   }
    133 }
    134 
    135 
    136 bool RSCheckAST::Validate() {
    137   clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
    138   for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(),
    139           DE = TUDecl->decls_end();
    140        DI != DE;
    141        DI++) {
    142     if (!SlangRS::IsLocInRSHeaderFile(DI->getLocStart(), mSM)) {
    143       if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*DI)) {
    144         ValidateVarDecl(VD);
    145       } else if (clang::FunctionDecl *FD =
    146             llvm::dyn_cast<clang::FunctionDecl>(*DI)) {
    147         ValidateFunctionDecl(FD);
    148       } else if (clang::Stmt *Body = (*DI)->getBody()) {
    149         Visit(Body);
    150       }
    151     }
    152   }
    153 
    154   return mValid;
    155 }
    156 
    157 }  // namespace slang
    158