• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
VisitStmt(clang::Stmt * S)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 
ValidateFunctionDecl(clang::FunctionDecl * FD)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 
ValidateVarDecl(clang::VarDecl * VD)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 
VisitDeclStmt(clang::DeclStmt * DS)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 
VisitExpr(clang::Expr * E)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 
Validate()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