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 23namespace slang { 24 25void 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 38void 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 77void 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 100void 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 117void 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 136bool 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