blob: c4fc0f3867518b65526542d02da25d5daa918ce9 [file] [log] [blame]
Zonr Changc383a502010-10-12 01:52:08 +08001/*
2 * Copyright 2010, 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
Zonr Chang3a9ca1f2010-10-06 17:52:56 +080017#include "slang_rs.h"
18
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070019#include <cstring>
Stephen Hinese639eb52010-11-08 19:27:20 -080020#include <list>
21#include <string>
22#include <utility>
23#include <vector>
Stephen Hinesfcda2352010-10-19 16:49:32 -070024
Zonr Changcf6af6a2010-10-12 12:38:51 +080025#include "clang/Frontend/FrontendDiagnostic.h"
26
Zonr Chang3a9ca1f2010-10-06 17:52:56 +080027#include "clang/Sema/SemaDiagnostic.h"
28
Stephen Hinese639eb52010-11-08 19:27:20 -080029#include "llvm/System/Path.h"
30
Zonr Chang3a9ca1f2010-10-06 17:52:56 +080031#include "slang_rs_backend.h"
32#include "slang_rs_context.h"
Zonr Chang641558f2010-10-12 21:07:06 +080033#include "slang_rs_export_type.h"
Zonr Chang3a9ca1f2010-10-06 17:52:56 +080034
Stephen Hinese639eb52010-11-08 19:27:20 -080035namespace slang {
Zonr Chang3a9ca1f2010-10-06 17:52:56 +080036
Zonr Chang3c250c52010-10-07 12:19:23 +080037#define RS_HEADER_SUFFIX "rsh"
38
Zonr Chang3ab021f2010-10-18 22:32:15 +080039/* RS_HEADER_ENTRY(name, default_included) */
Zonr Chang3c250c52010-10-07 12:19:23 +080040#define ENUM_RS_HEADER() \
Zonr Chang3ab021f2010-10-18 22:32:15 +080041 RS_HEADER_ENTRY(rs_types, 1) \
42 RS_HEADER_ENTRY(rs_cl, 1) \
43 RS_HEADER_ENTRY(rs_core, 1) \
Stephen Hines12505232011-01-06 17:08:33 -080044 RS_HEADER_ENTRY(rs_math, 1) \
45 RS_HEADER_ENTRY(rs_time, 1) \
Zonr Chang3ab021f2010-10-18 22:32:15 +080046 RS_HEADER_ENTRY(rs_graphics, 0)
Zonr Chang3c250c52010-10-07 12:19:23 +080047
Zonr Changcf6af6a2010-10-12 12:38:51 +080048bool SlangRS::reflectToJava(const std::string &OutputPathBase,
49 const std::string &OutputPackageName,
50 std::string *RealPackageName) {
51 return mRSContext->reflectToJava(OutputPathBase,
52 OutputPackageName,
53 getInputFileName(),
54 getOutputFileName(),
55 RealPackageName);
56}
57
58bool SlangRS::generateBitcodeAccessor(const std::string &OutputPathBase,
59 const std::string &PackageName) {
60 RSSlangReflectUtils::BitCodeAccessorContext BCAccessorContext;
61
62 BCAccessorContext.rsFileName = getInputFileName().c_str();
63 BCAccessorContext.bcFileName = getOutputFileName().c_str();
64 BCAccessorContext.reflectPath = OutputPathBase.c_str();
65 BCAccessorContext.packageName = PackageName.c_str();
66 BCAccessorContext.bcStorage = BCST_JAVA_CODE; // Must be BCST_JAVA_CODE
67
68 return RSSlangReflectUtils::GenerateBitCodeAccessor(BCAccessorContext);
69}
70
Zonr Change86245a2010-10-12 21:42:13 +080071bool SlangRS::checkODR(const char *CurInputFile) {
Zonr Chang641558f2010-10-12 21:07:06 +080072 for (RSContext::ExportableList::iterator I = mRSContext->exportable_begin(),
73 E = mRSContext->exportable_end();
74 I != E;
75 I++) {
Stephen Hinesa858cb62011-01-17 12:17:51 -080076 RSExportable *RSE = *I;
77 if (RSE->getKind() != RSExportable::EX_TYPE)
Zonr Chang641558f2010-10-12 21:07:06 +080078 continue;
79
Stephen Hinesa858cb62011-01-17 12:17:51 -080080 RSExportType *ET = static_cast<RSExportType *>(RSE);
Zonr Chang641558f2010-10-12 21:07:06 +080081 if (ET->getClass() != RSExportType::ExportClassRecord)
82 continue;
83
84 RSExportRecordType *ERT = static_cast<RSExportRecordType *>(ET);
85
86 // Artificial record types (create by us not by user in the source) always
87 // conforms the ODR.
88 if (ERT->isArtificial())
89 continue;
90
91 // Key to lookup ERT in ReflectedDefinitions
92 llvm::StringRef RDKey(ERT->getName());
93 ReflectedDefinitionListTy::const_iterator RD =
94 ReflectedDefinitions.find(RDKey);
95
96 if (RD != ReflectedDefinitions.end()) {
97 const RSExportRecordType *Reflected = RD->getValue().first;
98 // There's a record (struct) with the same name reflected before. Enforce
99 // ODR checking - the Reflected must hold *exactly* the same "definition"
100 // as the one defined previously. We say two record types A and B have the
101 // same definition iff:
102 //
103 // struct A { struct B {
104 // Type(a1) a1, Type(b1) b1,
105 // Type(a2) a2, Type(b1) b2,
106 // ... ...
107 // Type(aN) aN Type(b3) b3,
108 // }; }
109 // Cond. #1. They have same number of fields, i.e., N = M;
110 // Cond. #2. for (i := 1 to N)
111 // Type(ai) = Type(bi) must hold;
112 // Cond. #3. for (i := 1 to N)
113 // Name(ai) = Name(bi) must hold;
114 //
115 // where,
116 // Type(F) = the type of field F and
117 // Name(F) = the field name.
118
119 bool PassODR = false;
120 // Cond. #1 and Cond. #2
121 if (Reflected->equals(ERT)) {
122 // Cond #3.
123 RSExportRecordType::const_field_iterator AI = Reflected->fields_begin(),
124 BI = ERT->fields_begin();
125
126 for (unsigned i = 0, e = Reflected->getFields().size(); i != e; i++) {
127 if ((*AI)->getName() != (*BI)->getName())
128 break;
129 AI++;
130 BI++;
131 }
132 PassODR = (AI == (Reflected->fields_end()));
133 }
134
135 if (!PassODR) {
136 getDiagnostics().Report(mDiagErrorODR) << Reflected->getName()
137 << getInputFileName()
138 << RD->getValue().second;
139 return false;
140 }
141 } else {
142 llvm::StringMapEntry<ReflectedDefinitionTy> *ME =
143 llvm::StringMapEntry<ReflectedDefinitionTy>::Create(RDKey.begin(),
144 RDKey.end());
Zonr Change86245a2010-10-12 21:42:13 +0800145 ME->setValue(std::make_pair(ERT, CurInputFile));
Zonr Chang641558f2010-10-12 21:07:06 +0800146
147 if (!ReflectedDefinitions.insert(ME))
148 delete ME;
149
150 // Take the ownership of ERT such that it won't be freed in ~RSContext().
151 ERT->keep();
152 }
Zonr Chang641558f2010-10-12 21:07:06 +0800153 }
154 return true;
155}
Zonr Changcf6af6a2010-10-12 12:38:51 +0800156
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800157void SlangRS::initDiagnostic() {
158 clang::Diagnostic &Diag = getDiagnostics();
Zonr Changcf6af6a2010-10-12 12:38:51 +0800159 if (Diag.setDiagnosticGroupMapping("implicit-function-declaration",
160 clang::diag::MAP_ERROR))
161 Diag.Report(clang::diag::warn_unknown_warning_option)
162 << "implicit-function-declaration";
163
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800164 Diag.setDiagnosticMapping(
165 clang::diag::ext_typecheck_convert_discards_qualifiers,
166 clang::diag::MAP_ERROR);
Zonr Chang641558f2010-10-12 21:07:06 +0800167
168 mDiagErrorInvalidOutputDepParameter =
169 Diag.getCustomDiagID(clang::Diagnostic::Error,
170 "invalid parameter for output dependencies files.");
171
172 mDiagErrorODR =
173 Diag.getCustomDiagID(clang::Diagnostic::Error,
174 "type '%0' in different translation unit (%1 v.s. "
175 "%2) has incompatible type definition");
176
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800177 return;
178}
179
180void SlangRS::initPreprocessor() {
181 clang::Preprocessor &PP = getPreprocessor();
182
Zonr Chang3c250c52010-10-07 12:19:23 +0800183 std::string RSH;
Zonr Chang3ab021f2010-10-18 22:32:15 +0800184#define RS_HEADER_ENTRY(name, default_included) \
185 if (default_included) \
186 RSH.append("#include \"" #name "."RS_HEADER_SUFFIX "\"\n");
187 ENUM_RS_HEADER()
Zonr Chang3c250c52010-10-07 12:19:23 +0800188#undef RS_HEADER_ENTRY
189 PP.setPredefines(RSH);
190
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800191 return;
192}
193
194void SlangRS::initASTContext() {
Stephen Hines9e5b5032010-11-03 13:19:14 -0700195 mRSContext = new RSContext(getPreprocessor(),
196 getASTContext(),
Stephen Hines3fd0a942011-01-18 12:27:39 -0800197 getTargetInfo(),
198 &mPragmas);
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800199 return;
200}
201
202clang::ASTConsumer
203*SlangRS::createBackend(const clang::CodeGenOptions& CodeGenOpts,
204 llvm::raw_ostream *OS,
205 Slang::OutputType OT) {
206 return new RSBackend(mRSContext,
Stephen Hinese639eb52010-11-08 19:27:20 -0800207 &getDiagnostics(),
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800208 CodeGenOpts,
209 getTargetOptions(),
Stephen Hines3fd0a942011-01-18 12:27:39 -0800210 &mPragmas,
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800211 OS,
212 OT,
213 getSourceManager(),
214 mAllowRSPrefix);
215}
216
Zonr Chang592a9542010-10-07 20:03:58 +0800217bool SlangRS::IsRSHeaderFile(const char *File) {
Zonr Chang3ab021f2010-10-18 22:32:15 +0800218#define RS_HEADER_ENTRY(name, default_included) \
219 if (::strcmp(File, #name "."RS_HEADER_SUFFIX) == 0) \
Zonr Chang592a9542010-10-07 20:03:58 +0800220 return true;
221ENUM_RS_HEADER()
222#undef RS_HEADER_ENTRY
Zonr Chang592a9542010-10-07 20:03:58 +0800223 return false;
224}
225
Stephen Hinesfcda2352010-10-19 16:49:32 -0700226bool SlangRS::IsFunctionInRSHeaderFile(const clang::FunctionDecl *FD,
227 const clang::SourceManager &SourceMgr) {
228 clang::FullSourceLoc FSL(FD->getLocStart(), SourceMgr);
229 clang::PresumedLoc PLoc = SourceMgr.getPresumedLoc(FSL);
230 llvm::sys::Path HeaderFilename(PLoc.getFilename());
231
232 return IsRSHeaderFile(HeaderFilename.getLast().data());
233}
234
Zonr Chang641558f2010-10-12 21:07:06 +0800235SlangRS::SlangRS() : Slang(), mRSContext(NULL), mAllowRSPrefix(false) {
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800236 return;
237}
238
Zonr Changcf6af6a2010-10-12 12:38:51 +0800239bool SlangRS::compile(
240 const std::list<std::pair<const char*, const char*> > &IOFiles,
241 const std::list<std::pair<const char*, const char*> > &DepFiles,
242 const std::vector<std::string> &IncludePaths,
243 const std::vector<std::string> &AdditionalDepTargets,
244 Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage,
245 bool AllowRSPrefix, bool OutputDep,
246 const std::string &JavaReflectionPathBase,
247 const std::string &JavaReflectionPackageName) {
248 if (IOFiles.empty())
249 return true;
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800250
Zonr Changcf6af6a2010-10-12 12:38:51 +0800251 if (OutputDep && (DepFiles.size() != IOFiles.size())) {
Zonr Chang641558f2010-10-12 21:07:06 +0800252 getDiagnostics().Report(mDiagErrorInvalidOutputDepParameter);
Zonr Changcf6af6a2010-10-12 12:38:51 +0800253 return false;
254 }
255
256 std::string RealPackageName;
257
258 const char *InputFile, *OutputFile, *BCOutputFile, *DepOutputFile;
259 std::list<std::pair<const char*, const char*> >::const_iterator
260 IOFileIter = IOFiles.begin(), DepFileIter = DepFiles.begin();
261
262 setIncludePaths(IncludePaths);
263 setOutputType(OutputType);
264 if (OutputDep)
265 setAdditionalDepTargets(AdditionalDepTargets);
266
267 mAllowRSPrefix = AllowRSPrefix;
268
269 for (unsigned i = 0, e = IOFiles.size(); i != e; i++) {
270 InputFile = IOFileIter->first;
271 OutputFile = IOFileIter->second;
272
273 reset();
274
275 if (!setInputSource(InputFile))
276 return false;
277
278 if (!setOutput(OutputFile))
279 return false;
280
281 if (OutputDep) {
282 BCOutputFile = DepFileIter->first;
283 DepOutputFile = DepFileIter->second;
284
285 setDepTargetBC(BCOutputFile);
286
287 if (!setDepOutput(DepOutputFile))
288 return false;
289
290 if (generateDepFile() > 0)
291 return false;
292
293 DepFileIter++;
294 }
295
296 if (Slang::compile() > 0)
297 return false;
298
299 if (OutputType != Slang::OT_Dependency) {
300 if (!reflectToJava(JavaReflectionPathBase,
301 JavaReflectionPackageName,
302 &RealPackageName))
303 return false;
304
305 if ((OutputType == Slang::OT_Bitcode) &&
306 (BitcodeStorage == BCST_JAVA_CODE) &&
307 !generateBitcodeAccessor(JavaReflectionPathBase,
308 RealPackageName.c_str()))
309 return false;
310 }
311
Zonr Change86245a2010-10-12 21:42:13 +0800312 if (!checkODR(InputFile))
Zonr Chang641558f2010-10-12 21:07:06 +0800313 return false;
314
Zonr Changcf6af6a2010-10-12 12:38:51 +0800315 IOFileIter++;
316 }
317
318 return true;
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800319}
320
Zonr Chang641558f2010-10-12 21:07:06 +0800321void SlangRS::reset() {
322 delete mRSContext;
323 mRSContext = NULL;
324 Slang::reset();
325 return;
326}
327
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800328SlangRS::~SlangRS() {
329 delete mRSContext;
Zonr Chang641558f2010-10-12 21:07:06 +0800330 for (ReflectedDefinitionListTy::iterator I = ReflectedDefinitions.begin(),
331 E = ReflectedDefinitions.end();
332 I != E;
333 I++) {
334 delete I->getValue().first;
335 }
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800336 return;
337}
Stephen Hinese639eb52010-11-08 19:27:20 -0800338
339} // namespace slang