/* * Copyright 2012, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "slang_rs_check_ast.h" #include "slang_assert.h" #include "slang_rs.h" #include "slang_rs_export_foreach.h" #include "slang_rs_export_type.h" namespace slang { void RSCheckAST::VisitStmt(clang::Stmt *S) { // This function does the actual iteration through all sub-Stmt's within // a given Stmt. Note that this function is skipped by all of the other // Visit* functions if we have already found a higher-level match. for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I != E; I++) { if (clang::Stmt *Child = *I) { Visit(Child); } } } void RSCheckAST::ValidateFunctionDecl(clang::FunctionDecl *FD) { if (!FD) { return; } if (mIsFilterscript) { // Validate parameters for Filterscript. size_t numParams = FD->getNumParams(); clang::QualType resultType = FD->getResultType().getCanonicalType(); // We use FD as our NamedDecl in the case of a bad return type. if (!RSExportType::ValidateType(C, resultType, FD, FD->getLocStart(), mTargetAPI, mIsFilterscript)) { mValid = false; } for (size_t i = 0; i < numParams; i++) { clang::ParmVarDecl *PVD = FD->getParamDecl(i); clang::QualType QT = PVD->getType().getCanonicalType(); if (!RSExportType::ValidateType(C, QT, PVD, PVD->getLocStart(), mTargetAPI, mIsFilterscript)) { mValid = false; } } } bool saveKernel = mInKernel; mInKernel = RSExportForEach::isRSForEachFunc(mTargetAPI, &mDiagEngine, FD); if (clang::Stmt *Body = FD->getBody()) { Visit(Body); } mInKernel = saveKernel; } void RSCheckAST::ValidateVarDecl(clang::VarDecl *VD) { if (!VD) { return; } clang::QualType QT = VD->getType(); if (VD->getLinkage() == clang::ExternalLinkage) { llvm::StringRef TypeName; const clang::Type *T = QT.getTypePtr(); if (!RSExportType::NormalizeType(T, TypeName, &mDiagEngine, VD)) { mValid = false; } } // We don't allow static (non-const) variables within kernels. if (mInKernel && VD->isStaticLocal()) { if (!QT.isConstQualified()) { mDiagEngine.Report( clang::FullSourceLoc(VD->getLocation(), mSM), mDiagEngine.getCustomDiagID( clang::DiagnosticsEngine::Error, "Non-const static variables are not allowed in kernels: '%0'")) << VD->getName(); mValid = false; } } if (!RSExportType::ValidateVarDecl(VD, mTargetAPI, mIsFilterscript)) { mValid = false; } else if (clang::Expr *Init = VD->getInit()) { // Only check the initializer if the decl is already ok. Visit(Init); } } void RSCheckAST::VisitDeclStmt(clang::DeclStmt *DS) { if (!SlangRS::IsLocInRSHeaderFile(DS->getLocStart(), mSM)) { for (clang::DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); I != E; ++I) { if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I)) { ValidateVarDecl(VD); } else if (clang::FunctionDecl *FD = llvm::dyn_cast<clang::FunctionDecl>(*I)) { ValidateFunctionDecl(FD); } } } } void RSCheckAST::VisitExpr(clang::Expr *E) { // This is where FS checks for code using pointer and/or 64-bit expressions // (i.e. things like casts). // First we skip implicit casts (things like function calls and explicit // array accesses rely heavily on them and they are valid. E = E->IgnoreImpCasts(); if (mIsFilterscript && !SlangRS::IsLocInRSHeaderFile(E->getExprLoc(), mSM) && !RSExportType::ValidateType(C, E->getType(), NULL, E->getExprLoc(), mTargetAPI, mIsFilterscript)) { mValid = false; } else { // Only visit sub-expressions if we haven't already seen a violation. VisitStmt(E); } } bool RSCheckAST::Validate() { clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl(); for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(), DE = TUDecl->decls_end(); DI != DE; DI++) { if (!SlangRS::IsLocInRSHeaderFile(DI->getLocStart(), mSM)) { if (clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*DI)) { ValidateVarDecl(VD); } else if (clang::FunctionDecl *FD = llvm::dyn_cast<clang::FunctionDecl>(*DI)) { ValidateFunctionDecl(FD); } else if (clang::Stmt *Body = (*DI)->getBody()) { Visit(Body); } } } return mValid; } } // namespace slang