slang_rs.cpp revision a858cb6f3d9223d65bf73e1230c6324ded4095f6
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 "slang_rs_backend.h" 32#include "slang_rs_context.h" 33#include "slang_rs_export_type.h" 34 35namespace slang { 36 37#define RS_HEADER_SUFFIX "rsh" 38 39/* RS_HEADER_ENTRY(name, default_included) */ 40#define ENUM_RS_HEADER() \ 41 RS_HEADER_ENTRY(rs_types, 1) \ 42 RS_HEADER_ENTRY(rs_cl, 1) \ 43 RS_HEADER_ENTRY(rs_core, 1) \ 44 RS_HEADER_ENTRY(rs_math, 1) \ 45 RS_HEADER_ENTRY(rs_time, 1) \ 46 RS_HEADER_ENTRY(rs_graphics, 0) 47 48bool 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 71bool SlangRS::checkODR(const char *CurInputFile) { 72 for (RSContext::ExportableList::iterator I = mRSContext->exportable_begin(), 73 E = mRSContext->exportable_end(); 74 I != E; 75 I++) { 76 RSExportable *RSE = *I; 77 if (RSE->getKind() != RSExportable::EX_TYPE) 78 continue; 79 80 RSExportType *ET = static_cast<RSExportType *>(RSE); 81 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()); 145 ME->setValue(std::make_pair(ERT, CurInputFile)); 146 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 } 153 } 154 return true; 155} 156 157void SlangRS::initDiagnostic() { 158 clang::Diagnostic &Diag = getDiagnostics(); 159 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 164 Diag.setDiagnosticMapping( 165 clang::diag::ext_typecheck_convert_discards_qualifiers, 166 clang::diag::MAP_ERROR); 167 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 177 return; 178} 179 180void SlangRS::initPreprocessor() { 181 clang::Preprocessor &PP = getPreprocessor(); 182 183 std::string RSH; 184#define RS_HEADER_ENTRY(name, default_included) \ 185 if (default_included) \ 186 RSH.append("#include \"" #name "."RS_HEADER_SUFFIX "\"\n"); 187 ENUM_RS_HEADER() 188#undef RS_HEADER_ENTRY 189 PP.setPredefines(RSH); 190 191 return; 192} 193 194void SlangRS::initASTContext() { 195 mRSContext = new RSContext(getPreprocessor(), 196 getASTContext(), 197 getTargetInfo()); 198 return; 199} 200 201clang::ASTConsumer 202*SlangRS::createBackend(const clang::CodeGenOptions& CodeGenOpts, 203 llvm::raw_ostream *OS, 204 Slang::OutputType OT) { 205 return new RSBackend(mRSContext, 206 &getDiagnostics(), 207 CodeGenOpts, 208 getTargetOptions(), 209 mPragmas, 210 OS, 211 OT, 212 getSourceManager(), 213 mAllowRSPrefix); 214} 215 216bool SlangRS::IsRSHeaderFile(const char *File) { 217#define RS_HEADER_ENTRY(name, default_included) \ 218 if (::strcmp(File, #name "."RS_HEADER_SUFFIX) == 0) \ 219 return true; 220ENUM_RS_HEADER() 221#undef RS_HEADER_ENTRY 222 return false; 223} 224 225bool SlangRS::IsFunctionInRSHeaderFile(const clang::FunctionDecl *FD, 226 const clang::SourceManager &SourceMgr) { 227 clang::FullSourceLoc FSL(FD->getLocStart(), SourceMgr); 228 clang::PresumedLoc PLoc = SourceMgr.getPresumedLoc(FSL); 229 llvm::sys::Path HeaderFilename(PLoc.getFilename()); 230 231 return IsRSHeaderFile(HeaderFilename.getLast().data()); 232} 233 234SlangRS::SlangRS() : Slang(), mRSContext(NULL), mAllowRSPrefix(false) { 235 return; 236} 237 238bool SlangRS::compile( 239 const std::list<std::pair<const char*, const char*> > &IOFiles, 240 const std::list<std::pair<const char*, const char*> > &DepFiles, 241 const std::vector<std::string> &IncludePaths, 242 const std::vector<std::string> &AdditionalDepTargets, 243 Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage, 244 bool AllowRSPrefix, bool OutputDep, 245 const std::string &JavaReflectionPathBase, 246 const std::string &JavaReflectionPackageName) { 247 if (IOFiles.empty()) 248 return true; 249 250 if (OutputDep && (DepFiles.size() != IOFiles.size())) { 251 getDiagnostics().Report(mDiagErrorInvalidOutputDepParameter); 252 return false; 253 } 254 255 std::string RealPackageName; 256 257 const char *InputFile, *OutputFile, *BCOutputFile, *DepOutputFile; 258 std::list<std::pair<const char*, const char*> >::const_iterator 259 IOFileIter = IOFiles.begin(), DepFileIter = DepFiles.begin(); 260 261 setIncludePaths(IncludePaths); 262 setOutputType(OutputType); 263 if (OutputDep) 264 setAdditionalDepTargets(AdditionalDepTargets); 265 266 mAllowRSPrefix = AllowRSPrefix; 267 268 for (unsigned i = 0, e = IOFiles.size(); i != e; i++) { 269 InputFile = IOFileIter->first; 270 OutputFile = IOFileIter->second; 271 272 reset(); 273 274 if (!setInputSource(InputFile)) 275 return false; 276 277 if (!setOutput(OutputFile)) 278 return false; 279 280 if (OutputDep) { 281 BCOutputFile = DepFileIter->first; 282 DepOutputFile = DepFileIter->second; 283 284 setDepTargetBC(BCOutputFile); 285 286 if (!setDepOutput(DepOutputFile)) 287 return false; 288 289 if (generateDepFile() > 0) 290 return false; 291 292 DepFileIter++; 293 } 294 295 if (Slang::compile() > 0) 296 return false; 297 298 if (OutputType != Slang::OT_Dependency) { 299 if (!reflectToJava(JavaReflectionPathBase, 300 JavaReflectionPackageName, 301 &RealPackageName)) 302 return false; 303 304 if ((OutputType == Slang::OT_Bitcode) && 305 (BitcodeStorage == BCST_JAVA_CODE) && 306 !generateBitcodeAccessor(JavaReflectionPathBase, 307 RealPackageName.c_str())) 308 return false; 309 } 310 311 if (!checkODR(InputFile)) 312 return false; 313 314 IOFileIter++; 315 } 316 317 return true; 318} 319 320void SlangRS::reset() { 321 delete mRSContext; 322 mRSContext = NULL; 323 Slang::reset(); 324 return; 325} 326 327SlangRS::~SlangRS() { 328 delete mRSContext; 329 for (ReflectedDefinitionListTy::iterator I = ReflectedDefinitions.begin(), 330 E = ReflectedDefinitions.end(); 331 I != E; 332 I++) { 333 delete I->getValue().first; 334 } 335 return; 336} 337 338} // namespace slang 339