slang_rs.cpp revision 8d5a2f6ab321615bfb3a46f68aff0b643a71caa0
1/* 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 17#include "slang_rs.h" 18 19#include <cstring> 20#include <list> 21#include <string> 22#include <utility> 23#include <vector> 24 25#include "clang/Frontend/FrontendDiagnostic.h" 26 27#include "clang/Sema/SemaDiagnostic.h" 28 29#include "llvm/System/Path.h" 30 31#include "os_sep.h" 32#include "slang_rs_backend.h" 33#include "slang_rs_context.h" 34#include "slang_rs_export_type.h" 35 36namespace slang { 37 38#define RS_HEADER_SUFFIX "rsh" 39 40/* RS_HEADER_ENTRY(name, default_included) */ 41#define ENUM_RS_HEADER() \ 42 RS_HEADER_ENTRY(rs_types, 1) \ 43 RS_HEADER_ENTRY(rs_cl, 1) \ 44 RS_HEADER_ENTRY(rs_core, 1) \ 45 RS_HEADER_ENTRY(rs_math, 1) \ 46 RS_HEADER_ENTRY(rs_time, 1) \ 47 RS_HEADER_ENTRY(rs_graphics, 0) 48 49bool SlangRS::reflectToJava(const std::string &OutputPathBase, 50 const std::string &OutputPackageName, 51 std::string *RealPackageName) { 52 return mRSContext->reflectToJava(OutputPathBase, 53 OutputPackageName, 54 getInputFileName(), 55 getOutputFileName(), 56 RealPackageName); 57} 58 59bool SlangRS::generateBitcodeAccessor(const std::string &OutputPathBase, 60 const std::string &PackageName) { 61 RSSlangReflectUtils::BitCodeAccessorContext BCAccessorContext; 62 63 BCAccessorContext.rsFileName = getInputFileName().c_str(); 64 BCAccessorContext.bcFileName = getOutputFileName().c_str(); 65 BCAccessorContext.reflectPath = OutputPathBase.c_str(); 66 BCAccessorContext.packageName = PackageName.c_str(); 67 BCAccessorContext.bcStorage = BCST_JAVA_CODE; // Must be BCST_JAVA_CODE 68 69 return RSSlangReflectUtils::GenerateBitCodeAccessor(BCAccessorContext); 70} 71 72bool SlangRS::checkODR(const char *CurInputFile) { 73 for (RSContext::ExportableList::iterator I = mRSContext->exportable_begin(), 74 E = mRSContext->exportable_end(); 75 I != E; 76 I++) { 77 RSExportable *RSE = *I; 78 if (RSE->getKind() != RSExportable::EX_TYPE) 79 continue; 80 81 RSExportType *ET = static_cast<RSExportType *>(RSE); 82 if (ET->getClass() != RSExportType::ExportClassRecord) 83 continue; 84 85 RSExportRecordType *ERT = static_cast<RSExportRecordType *>(ET); 86 87 // Artificial record types (create by us not by user in the source) always 88 // conforms the ODR. 89 if (ERT->isArtificial()) 90 continue; 91 92 // Key to lookup ERT in ReflectedDefinitions 93 llvm::StringRef RDKey(ERT->getName()); 94 ReflectedDefinitionListTy::const_iterator RD = 95 ReflectedDefinitions.find(RDKey); 96 97 if (RD != ReflectedDefinitions.end()) { 98 const RSExportRecordType *Reflected = RD->getValue().first; 99 // There's a record (struct) with the same name reflected before. Enforce 100 // ODR checking - the Reflected must hold *exactly* the same "definition" 101 // as the one defined previously. We say two record types A and B have the 102 // same definition iff: 103 // 104 // struct A { struct B { 105 // Type(a1) a1, Type(b1) b1, 106 // Type(a2) a2, Type(b1) b2, 107 // ... ... 108 // Type(aN) aN Type(b3) b3, 109 // }; } 110 // Cond. #1. They have same number of fields, i.e., N = M; 111 // Cond. #2. for (i := 1 to N) 112 // Type(ai) = Type(bi) must hold; 113 // Cond. #3. for (i := 1 to N) 114 // Name(ai) = Name(bi) must hold; 115 // 116 // where, 117 // Type(F) = the type of field F and 118 // Name(F) = the field name. 119 120 bool PassODR = false; 121 // Cond. #1 and Cond. #2 122 if (Reflected->equals(ERT)) { 123 // Cond #3. 124 RSExportRecordType::const_field_iterator AI = Reflected->fields_begin(), 125 BI = ERT->fields_begin(); 126 127 for (unsigned i = 0, e = Reflected->getFields().size(); i != e; i++) { 128 if ((*AI)->getName() != (*BI)->getName()) 129 break; 130 AI++; 131 BI++; 132 } 133 PassODR = (AI == (Reflected->fields_end())); 134 } 135 136 if (!PassODR) { 137 getDiagnostics().Report(mDiagErrorODR) << Reflected->getName() 138 << getInputFileName() 139 << RD->getValue().second; 140 return false; 141 } 142 } else { 143 llvm::StringMapEntry<ReflectedDefinitionTy> *ME = 144 llvm::StringMapEntry<ReflectedDefinitionTy>::Create(RDKey.begin(), 145 RDKey.end()); 146 ME->setValue(std::make_pair(ERT, CurInputFile)); 147 148 if (!ReflectedDefinitions.insert(ME)) 149 delete ME; 150 151 // Take the ownership of ERT such that it won't be freed in ~RSContext(). 152 ERT->keep(); 153 } 154 } 155 return true; 156} 157 158void SlangRS::initDiagnostic() { 159 clang::Diagnostic &Diag = getDiagnostics(); 160 if (Diag.setDiagnosticGroupMapping("implicit-function-declaration", 161 clang::diag::MAP_ERROR)) 162 Diag.Report(clang::diag::warn_unknown_warning_option) 163 << "implicit-function-declaration"; 164 165 Diag.setDiagnosticMapping( 166 clang::diag::ext_typecheck_convert_discards_qualifiers, 167 clang::diag::MAP_ERROR); 168 169 mDiagErrorInvalidOutputDepParameter = 170 Diag.getCustomDiagID(clang::Diagnostic::Error, 171 "invalid parameter for output dependencies files."); 172 173 mDiagErrorODR = 174 Diag.getCustomDiagID(clang::Diagnostic::Error, 175 "type '%0' in different translation unit (%1 v.s. " 176 "%2) has incompatible type definition"); 177 178 return; 179} 180 181void SlangRS::initPreprocessor() { 182 clang::Preprocessor &PP = getPreprocessor(); 183 184 std::string RSH; 185#define RS_HEADER_ENTRY(name, default_included) \ 186 if (default_included) \ 187 RSH.append("#include \"" #name "."RS_HEADER_SUFFIX "\"\n"); 188 ENUM_RS_HEADER() 189#undef RS_HEADER_ENTRY 190 PP.setPredefines(RSH); 191 192 return; 193} 194 195void SlangRS::initASTContext() { 196 mRSContext = new RSContext(getPreprocessor(), 197 getASTContext(), 198 getTargetInfo(), 199 &mPragmas, 200 &mGeneratedFileNames); 201 return; 202} 203 204clang::ASTConsumer 205*SlangRS::createBackend(const clang::CodeGenOptions& CodeGenOpts, 206 llvm::raw_ostream *OS, 207 Slang::OutputType OT) { 208 return new RSBackend(mRSContext, 209 &getDiagnostics(), 210 CodeGenOpts, 211 getTargetOptions(), 212 &mPragmas, 213 OS, 214 OT, 215 getSourceManager(), 216 mAllowRSPrefix); 217} 218 219bool SlangRS::IsRSHeaderFile(const char *File) { 220#define RS_HEADER_ENTRY(name, default_included) \ 221 if (::strcmp(File, #name "."RS_HEADER_SUFFIX) == 0) \ 222 return true; 223ENUM_RS_HEADER() 224#undef RS_HEADER_ENTRY 225 return false; 226} 227 228bool SlangRS::IsFunctionInRSHeaderFile(const clang::FunctionDecl *FD, 229 const clang::SourceManager &SourceMgr) { 230 clang::FullSourceLoc FSL(FD->getLocStart(), SourceMgr); 231 clang::PresumedLoc PLoc = SourceMgr.getPresumedLoc(FSL); 232 llvm::sys::Path HeaderFilename(PLoc.getFilename()); 233 234 return IsRSHeaderFile(HeaderFilename.getLast().data()); 235} 236 237SlangRS::SlangRS() : Slang(), mRSContext(NULL), mAllowRSPrefix(false) { 238 return; 239} 240 241bool SlangRS::compile( 242 const std::list<std::pair<const char*, const char*> > &IOFiles, 243 const std::list<std::pair<const char*, const char*> > &DepFiles, 244 const std::vector<std::string> &IncludePaths, 245 const std::vector<std::string> &AdditionalDepTargets, 246 Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage, 247 bool AllowRSPrefix, bool OutputDep, 248 const std::string &JavaReflectionPathBase, 249 const std::string &JavaReflectionPackageName) { 250 if (IOFiles.empty()) 251 return true; 252 253 if (OutputDep && (DepFiles.size() != IOFiles.size())) { 254 getDiagnostics().Report(mDiagErrorInvalidOutputDepParameter); 255 return false; 256 } 257 258 std::string RealPackageName; 259 260 const char *InputFile, *OutputFile, *BCOutputFile, *DepOutputFile; 261 std::list<std::pair<const char*, const char*> >::const_iterator 262 IOFileIter = IOFiles.begin(), DepFileIter = DepFiles.begin(); 263 264 setIncludePaths(IncludePaths); 265 setOutputType(OutputType); 266 if (OutputDep) { 267 setAdditionalDepTargets(AdditionalDepTargets); 268 } 269 270 mAllowRSPrefix = AllowRSPrefix; 271 272 for (unsigned i = 0, e = IOFiles.size(); i != e; i++) { 273 InputFile = IOFileIter->first; 274 OutputFile = IOFileIter->second; 275 276 reset(); 277 278 if (!setInputSource(InputFile)) 279 return false; 280 281 if (!setOutput(OutputFile)) 282 return false; 283 284 if (Slang::compile() > 0) 285 return false; 286 287 if (OutputType != Slang::OT_Dependency) { 288 if (!reflectToJava(JavaReflectionPathBase, 289 JavaReflectionPackageName, 290 &RealPackageName)) 291 return false; 292 293 for (std::vector<std::string>::const_iterator 294 I = mGeneratedFileNames.begin(), E = mGeneratedFileNames.end(); 295 I != E; 296 I++) { 297 std::string ReflectedName = RSSlangReflectUtils::ComputePackagedPath( 298 JavaReflectionPathBase.c_str(), 299 (RealPackageName + OS_PATH_SEPARATOR_STR + *I).c_str()); 300 appendGeneratedFileName(ReflectedName + ".java"); 301 } 302 303 if ((OutputType == Slang::OT_Bitcode) && 304 (BitcodeStorage == BCST_JAVA_CODE) && 305 !generateBitcodeAccessor(JavaReflectionPathBase, 306 RealPackageName.c_str())) 307 return false; 308 } 309 310 if (OutputDep) { 311 BCOutputFile = DepFileIter->first; 312 DepOutputFile = DepFileIter->second; 313 314 setDepTargetBC(BCOutputFile); 315 316 if (!setDepOutput(DepOutputFile)) 317 return false; 318 319 if (generateDepFile() > 0) 320 return false; 321 322 DepFileIter++; 323 } 324 325 if (!checkODR(InputFile)) 326 return false; 327 328 IOFileIter++; 329 } 330 331 return true; 332} 333 334void SlangRS::reset() { 335 delete mRSContext; 336 mRSContext = NULL; 337 mGeneratedFileNames.clear(); 338 Slang::reset(); 339 return; 340} 341 342SlangRS::~SlangRS() { 343 delete mRSContext; 344 for (ReflectedDefinitionListTy::iterator I = ReflectedDefinitions.begin(), 345 E = ReflectedDefinitions.end(); 346 I != E; 347 I++) { 348 delete I->getValue().first; 349 } 350 return; 351} 352 353} // namespace slang 354