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