blob: 7945f957ba0584b2627376dd0303fe298bea4974 [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
Loganbe274822011-02-16 22:02:54 +080025#include "clang/Basic/SourceLocation.h"
26
Zonr Changcf6af6a2010-10-12 12:38:51 +080027#include "clang/Frontend/FrontendDiagnostic.h"
28
Zonr Chang3a9ca1f2010-10-06 17:52:56 +080029#include "clang/Sema/SemaDiagnostic.h"
30
Loganbe274822011-02-16 22:02:54 +080031#include "llvm/Support/Path.h"
Stephen Hinese639eb52010-11-08 19:27:20 -080032
Raphael8d5a2f62011-02-08 00:15:05 -080033#include "os_sep.h"
Zonr Chang3a9ca1f2010-10-06 17:52:56 +080034#include "slang_rs_backend.h"
35#include "slang_rs_context.h"
Zonr Chang641558f2010-10-12 21:07:06 +080036#include "slang_rs_export_type.h"
Zonr Chang3a9ca1f2010-10-06 17:52:56 +080037
Stephen Hinese639eb52010-11-08 19:27:20 -080038namespace slang {
Zonr Chang3a9ca1f2010-10-06 17:52:56 +080039
Zonr Chang3c250c52010-10-07 12:19:23 +080040#define RS_HEADER_SUFFIX "rsh"
41
Zonr Chang3ab021f2010-10-18 22:32:15 +080042/* RS_HEADER_ENTRY(name, default_included) */
Zonr Chang3c250c52010-10-07 12:19:23 +080043#define ENUM_RS_HEADER() \
Zonr Chang3ab021f2010-10-18 22:32:15 +080044 RS_HEADER_ENTRY(rs_types, 1) \
45 RS_HEADER_ENTRY(rs_cl, 1) \
46 RS_HEADER_ENTRY(rs_core, 1) \
Stephen Hines12505232011-01-06 17:08:33 -080047 RS_HEADER_ENTRY(rs_math, 1) \
48 RS_HEADER_ENTRY(rs_time, 1) \
Zonr Chang3ab021f2010-10-18 22:32:15 +080049 RS_HEADER_ENTRY(rs_graphics, 0)
Zonr Chang3c250c52010-10-07 12:19:23 +080050
Zonr Changcf6af6a2010-10-12 12:38:51 +080051bool SlangRS::reflectToJava(const std::string &OutputPathBase,
52 const std::string &OutputPackageName,
53 std::string *RealPackageName) {
54 return mRSContext->reflectToJava(OutputPathBase,
55 OutputPackageName,
56 getInputFileName(),
57 getOutputFileName(),
58 RealPackageName);
59}
60
61bool SlangRS::generateBitcodeAccessor(const std::string &OutputPathBase,
62 const std::string &PackageName) {
63 RSSlangReflectUtils::BitCodeAccessorContext BCAccessorContext;
64
65 BCAccessorContext.rsFileName = getInputFileName().c_str();
66 BCAccessorContext.bcFileName = getOutputFileName().c_str();
67 BCAccessorContext.reflectPath = OutputPathBase.c_str();
68 BCAccessorContext.packageName = PackageName.c_str();
69 BCAccessorContext.bcStorage = BCST_JAVA_CODE; // Must be BCST_JAVA_CODE
70
71 return RSSlangReflectUtils::GenerateBitCodeAccessor(BCAccessorContext);
72}
73
Zonr Change86245a2010-10-12 21:42:13 +080074bool SlangRS::checkODR(const char *CurInputFile) {
Zonr Chang641558f2010-10-12 21:07:06 +080075 for (RSContext::ExportableList::iterator I = mRSContext->exportable_begin(),
76 E = mRSContext->exportable_end();
77 I != E;
78 I++) {
Stephen Hinesa858cb62011-01-17 12:17:51 -080079 RSExportable *RSE = *I;
80 if (RSE->getKind() != RSExportable::EX_TYPE)
Zonr Chang641558f2010-10-12 21:07:06 +080081 continue;
82
Stephen Hinesa858cb62011-01-17 12:17:51 -080083 RSExportType *ET = static_cast<RSExportType *>(RSE);
Zonr Chang641558f2010-10-12 21:07:06 +080084 if (ET->getClass() != RSExportType::ExportClassRecord)
85 continue;
86
87 RSExportRecordType *ERT = static_cast<RSExportRecordType *>(ET);
88
89 // Artificial record types (create by us not by user in the source) always
90 // conforms the ODR.
91 if (ERT->isArtificial())
92 continue;
93
94 // Key to lookup ERT in ReflectedDefinitions
95 llvm::StringRef RDKey(ERT->getName());
96 ReflectedDefinitionListTy::const_iterator RD =
97 ReflectedDefinitions.find(RDKey);
98
99 if (RD != ReflectedDefinitions.end()) {
100 const RSExportRecordType *Reflected = RD->getValue().first;
101 // There's a record (struct) with the same name reflected before. Enforce
102 // ODR checking - the Reflected must hold *exactly* the same "definition"
103 // as the one defined previously. We say two record types A and B have the
104 // same definition iff:
105 //
106 // struct A { struct B {
107 // Type(a1) a1, Type(b1) b1,
108 // Type(a2) a2, Type(b1) b2,
109 // ... ...
110 // Type(aN) aN Type(b3) b3,
111 // }; }
112 // Cond. #1. They have same number of fields, i.e., N = M;
113 // Cond. #2. for (i := 1 to N)
114 // Type(ai) = Type(bi) must hold;
115 // Cond. #3. for (i := 1 to N)
116 // Name(ai) = Name(bi) must hold;
117 //
118 // where,
119 // Type(F) = the type of field F and
120 // Name(F) = the field name.
121
122 bool PassODR = false;
123 // Cond. #1 and Cond. #2
124 if (Reflected->equals(ERT)) {
125 // Cond #3.
126 RSExportRecordType::const_field_iterator AI = Reflected->fields_begin(),
127 BI = ERT->fields_begin();
128
129 for (unsigned i = 0, e = Reflected->getFields().size(); i != e; i++) {
130 if ((*AI)->getName() != (*BI)->getName())
131 break;
132 AI++;
133 BI++;
134 }
135 PassODR = (AI == (Reflected->fields_end()));
136 }
137
138 if (!PassODR) {
139 getDiagnostics().Report(mDiagErrorODR) << Reflected->getName()
140 << getInputFileName()
141 << RD->getValue().second;
142 return false;
143 }
144 } else {
145 llvm::StringMapEntry<ReflectedDefinitionTy> *ME =
146 llvm::StringMapEntry<ReflectedDefinitionTy>::Create(RDKey.begin(),
147 RDKey.end());
Zonr Change86245a2010-10-12 21:42:13 +0800148 ME->setValue(std::make_pair(ERT, CurInputFile));
Zonr Chang641558f2010-10-12 21:07:06 +0800149
150 if (!ReflectedDefinitions.insert(ME))
151 delete ME;
152
153 // Take the ownership of ERT such that it won't be freed in ~RSContext().
154 ERT->keep();
155 }
Zonr Chang641558f2010-10-12 21:07:06 +0800156 }
157 return true;
158}
Zonr Changcf6af6a2010-10-12 12:38:51 +0800159
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800160void SlangRS::initDiagnostic() {
161 clang::Diagnostic &Diag = getDiagnostics();
Zonr Changcf6af6a2010-10-12 12:38:51 +0800162 if (Diag.setDiagnosticGroupMapping("implicit-function-declaration",
163 clang::diag::MAP_ERROR))
164 Diag.Report(clang::diag::warn_unknown_warning_option)
165 << "implicit-function-declaration";
166
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800167 Diag.setDiagnosticMapping(
168 clang::diag::ext_typecheck_convert_discards_qualifiers,
Loganbe274822011-02-16 22:02:54 +0800169 clang::diag::MAP_ERROR,
170 clang::SourceLocation());
Zonr Chang641558f2010-10-12 21:07:06 +0800171
172 mDiagErrorInvalidOutputDepParameter =
173 Diag.getCustomDiagID(clang::Diagnostic::Error,
174 "invalid parameter for output dependencies files.");
175
176 mDiagErrorODR =
177 Diag.getCustomDiagID(clang::Diagnostic::Error,
178 "type '%0' in different translation unit (%1 v.s. "
179 "%2) has incompatible type definition");
180
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800181 return;
182}
183
184void SlangRS::initPreprocessor() {
185 clang::Preprocessor &PP = getPreprocessor();
186
Zonr Chang3c250c52010-10-07 12:19:23 +0800187 std::string RSH;
Zonr Chang3ab021f2010-10-18 22:32:15 +0800188#define RS_HEADER_ENTRY(name, default_included) \
189 if (default_included) \
190 RSH.append("#include \"" #name "."RS_HEADER_SUFFIX "\"\n");
191 ENUM_RS_HEADER()
Zonr Chang3c250c52010-10-07 12:19:23 +0800192#undef RS_HEADER_ENTRY
193 PP.setPredefines(RSH);
194
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800195 return;
196}
197
198void SlangRS::initASTContext() {
Stephen Hines9e5b5032010-11-03 13:19:14 -0700199 mRSContext = new RSContext(getPreprocessor(),
200 getASTContext(),
Stephen Hines3fd0a942011-01-18 12:27:39 -0800201 getTargetInfo(),
Stephen Hines4cc67fc2011-01-31 16:48:57 -0800202 &mPragmas,
203 &mGeneratedFileNames);
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800204 return;
205}
206
207clang::ASTConsumer
208*SlangRS::createBackend(const clang::CodeGenOptions& CodeGenOpts,
209 llvm::raw_ostream *OS,
210 Slang::OutputType OT) {
211 return new RSBackend(mRSContext,
Stephen Hinese639eb52010-11-08 19:27:20 -0800212 &getDiagnostics(),
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800213 CodeGenOpts,
214 getTargetOptions(),
Stephen Hines3fd0a942011-01-18 12:27:39 -0800215 &mPragmas,
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800216 OS,
217 OT,
218 getSourceManager(),
219 mAllowRSPrefix);
220}
221
Zonr Chang592a9542010-10-07 20:03:58 +0800222bool SlangRS::IsRSHeaderFile(const char *File) {
Zonr Chang3ab021f2010-10-18 22:32:15 +0800223#define RS_HEADER_ENTRY(name, default_included) \
224 if (::strcmp(File, #name "."RS_HEADER_SUFFIX) == 0) \
Zonr Chang592a9542010-10-07 20:03:58 +0800225 return true;
226ENUM_RS_HEADER()
227#undef RS_HEADER_ENTRY
Zonr Chang592a9542010-10-07 20:03:58 +0800228 return false;
229}
230
Stephen Hinesfcda2352010-10-19 16:49:32 -0700231bool SlangRS::IsFunctionInRSHeaderFile(const clang::FunctionDecl *FD,
232 const clang::SourceManager &SourceMgr) {
233 clang::FullSourceLoc FSL(FD->getLocStart(), SourceMgr);
234 clang::PresumedLoc PLoc = SourceMgr.getPresumedLoc(FSL);
Stephen Hinesfcda2352010-10-19 16:49:32 -0700235
Logan Chien6f4e0a92011-03-10 01:10:25 +0800236 return IsRSHeaderFile(llvm::sys::path::filename(PLoc.getFilename()).data());
Stephen Hinesfcda2352010-10-19 16:49:32 -0700237}
238
Zonr Chang641558f2010-10-12 21:07:06 +0800239SlangRS::SlangRS() : Slang(), mRSContext(NULL), mAllowRSPrefix(false) {
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800240 return;
241}
242
Zonr Changcf6af6a2010-10-12 12:38:51 +0800243bool SlangRS::compile(
244 const std::list<std::pair<const char*, const char*> > &IOFiles,
245 const std::list<std::pair<const char*, const char*> > &DepFiles,
246 const std::vector<std::string> &IncludePaths,
247 const std::vector<std::string> &AdditionalDepTargets,
248 Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage,
249 bool AllowRSPrefix, bool OutputDep,
250 const std::string &JavaReflectionPathBase,
251 const std::string &JavaReflectionPackageName) {
252 if (IOFiles.empty())
253 return true;
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800254
Zonr Changcf6af6a2010-10-12 12:38:51 +0800255 if (OutputDep && (DepFiles.size() != IOFiles.size())) {
Zonr Chang641558f2010-10-12 21:07:06 +0800256 getDiagnostics().Report(mDiagErrorInvalidOutputDepParameter);
Zonr Changcf6af6a2010-10-12 12:38:51 +0800257 return false;
258 }
259
260 std::string RealPackageName;
261
262 const char *InputFile, *OutputFile, *BCOutputFile, *DepOutputFile;
263 std::list<std::pair<const char*, const char*> >::const_iterator
264 IOFileIter = IOFiles.begin(), DepFileIter = DepFiles.begin();
265
266 setIncludePaths(IncludePaths);
267 setOutputType(OutputType);
Stephen Hines4cc67fc2011-01-31 16:48:57 -0800268 if (OutputDep) {
Zonr Changcf6af6a2010-10-12 12:38:51 +0800269 setAdditionalDepTargets(AdditionalDepTargets);
Stephen Hines4cc67fc2011-01-31 16:48:57 -0800270 }
Zonr Changcf6af6a2010-10-12 12:38:51 +0800271
272 mAllowRSPrefix = AllowRSPrefix;
273
274 for (unsigned i = 0, e = IOFiles.size(); i != e; i++) {
275 InputFile = IOFileIter->first;
276 OutputFile = IOFileIter->second;
277
278 reset();
279
280 if (!setInputSource(InputFile))
281 return false;
282
283 if (!setOutput(OutputFile))
284 return false;
285
Stephen Hines4cc67fc2011-01-31 16:48:57 -0800286 if (Slang::compile() > 0)
287 return false;
288
289 if (OutputType != Slang::OT_Dependency) {
290 if (!reflectToJava(JavaReflectionPathBase,
291 JavaReflectionPackageName,
292 &RealPackageName))
293 return false;
294
295 for (std::vector<std::string>::const_iterator
296 I = mGeneratedFileNames.begin(), E = mGeneratedFileNames.end();
297 I != E;
298 I++) {
299 std::string ReflectedName = RSSlangReflectUtils::ComputePackagedPath(
300 JavaReflectionPathBase.c_str(),
Raphael8d5a2f62011-02-08 00:15:05 -0800301 (RealPackageName + OS_PATH_SEPARATOR_STR + *I).c_str());
Stephen Hines4cc67fc2011-01-31 16:48:57 -0800302 appendGeneratedFileName(ReflectedName + ".java");
303 }
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 Changcf6af6a2010-10-12 12:38:51 +0800312 if (OutputDep) {
313 BCOutputFile = DepFileIter->first;
314 DepOutputFile = DepFileIter->second;
315
316 setDepTargetBC(BCOutputFile);
317
318 if (!setDepOutput(DepOutputFile))
319 return false;
320
321 if (generateDepFile() > 0)
322 return false;
323
324 DepFileIter++;
325 }
326
Zonr Change86245a2010-10-12 21:42:13 +0800327 if (!checkODR(InputFile))
Zonr Chang641558f2010-10-12 21:07:06 +0800328 return false;
329
Zonr Changcf6af6a2010-10-12 12:38:51 +0800330 IOFileIter++;
331 }
332
333 return true;
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800334}
335
Zonr Chang641558f2010-10-12 21:07:06 +0800336void SlangRS::reset() {
337 delete mRSContext;
338 mRSContext = NULL;
Stephen Hines4cc67fc2011-01-31 16:48:57 -0800339 mGeneratedFileNames.clear();
Zonr Chang641558f2010-10-12 21:07:06 +0800340 Slang::reset();
341 return;
342}
343
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800344SlangRS::~SlangRS() {
345 delete mRSContext;
Zonr Chang641558f2010-10-12 21:07:06 +0800346 for (ReflectedDefinitionListTy::iterator I = ReflectedDefinitions.begin(),
347 E = ReflectedDefinitions.end();
348 I != E;
349 I++) {
350 delete I->getValue().first;
351 }
Zonr Chang3a9ca1f2010-10-06 17:52:56 +0800352 return;
353}
Stephen Hinese639eb52010-11-08 19:27:20 -0800354
355} // namespace slang