/// Skip a type suffix that can be dropped. static Optional<StringRef> skipTypeSuffix(StringRef typeName) { if (typeName.empty()) return None; auto lastWord = camel_case::getLastWord(typeName); // "Type" suffix. if (lastWord == "Type" && typeName.size() > 4) { return typeName.drop_back(4); } // "Ref" suffix. if (lastWord == "Ref" && typeName.size() > 3) { return typeName.drop_back(3); } // \d+D for dimensionality. if (typeName.back() == 'D' && typeName.size() > 1) { unsigned firstDigit = typeName.size() - 1; while (firstDigit > 0) { if (!isdigit(typeName[firstDigit-1])) break; --firstDigit; } if (firstDigit < typeName.size()-1) { return typeName.substr(0, firstDigit); } } // _t. if (typeName.size() > 2 && typeName.endswith("_t")) { return typeName.drop_back(2); } return None; }
// Returns true if S matches /Filename.?\.o$/. static bool isCrtBeginEnd(StringRef S, StringRef Filename) { if (!S.endswith(".o")) return false; S = S.drop_back(2); if (S.endswith(Filename)) return true; return !S.empty() && S.drop_back().endswith(Filename); }
static bool matchCrtObjName(StringRef objName, StringRef objPath) { if (!objPath.endswith(".o")) return false; // check *<objName> case objPath = objPath.drop_back(2); if (objPath.endswith(objName)) return true; // check *<objName>? case return !objPath.empty() && objPath.drop_back(1).endswith(objName); }
/// \brief Tries to find the node under this \c FileMatchTrieNode that best /// matches 'FileName'. /// /// If multiple paths fit 'FileName' equally well, \c IsAmbiguous is set to /// \c true and an empty string is returned. If no path fits 'FileName', an /// empty string is returned. \c ConsumedLength denotes the number of /// \c Filename's trailing characters already consumed during recursion. /// /// To find the best matching node for a given path 'p', the /// \c findEquivalent() function is called recursively for each path segment /// (back to fron) of 'p' until a node 'n' is reached that does not .. /// - .. have children. In this case it is checked /// whether the stored path is equivalent to 'p'. If yes, the best match is /// found. Otherwise continue with the parent node as if this node did not /// exist. /// - .. a child matching the next path segment. In this case, all children of /// 'n' are an equally good match for 'p'. All children are of 'n' are found /// recursively and their equivalence to 'p' is determined. If none are /// equivalent, continue with the parent node as if 'n' didn't exist. If one /// is equivalent, the best match is found. Otherwise, report and ambigiuity /// error. StringRef findEquivalent(const PathComparator& Comparator, StringRef FileName, bool &IsAmbiguous, unsigned ConsumedLength = 0) const { if (Children.empty()) { if (Comparator.equivalent(StringRef(Path), FileName)) return StringRef(Path); return StringRef(); } StringRef Element(llvm::sys::path::filename(FileName.drop_back( ConsumedLength))); llvm::StringMap<FileMatchTrieNode>::const_iterator MatchingChild = Children.find(Element); if (MatchingChild != Children.end()) { StringRef Result = MatchingChild->getValue().findEquivalent( Comparator, FileName, IsAmbiguous, ConsumedLength + Element.size() + 1); if (!Result.empty() || IsAmbiguous) return Result; } std::vector<StringRef> AllChildren; getAll(AllChildren, MatchingChild); StringRef Result; for (unsigned i = 0; i < AllChildren.size(); i++) { if (Comparator.equivalent(AllChildren[i], FileName)) { if (Result.empty()) { Result = AllChildren[i]; } else { IsAmbiguous = true; return StringRef(); } } } return Result; }
StringRef getStringArg(Value *v) { const Value *g = cast<Constant>(v)->stripPointerCasts(); const Constant *ptr = cast<GlobalVariable>(g)->getInitializer(); StringRef str = cast<ConstantDataSequential>(ptr)->getAsString(); // Drop the '\0' at the end return str.drop_back(); }
static bool matchesStyle(StringRef Name, IdentifierNamingCheck::NamingStyle Style) { static llvm::Regex Matchers[] = { llvm::Regex("^.*$"), llvm::Regex("^[a-z][a-z0-9_]*$"), llvm::Regex("^[a-z][a-zA-Z0-9]*$"), llvm::Regex("^[A-Z][A-Z0-9_]*$"), llvm::Regex("^[A-Z][a-zA-Z0-9]*$"), llvm::Regex("^[A-Z]([a-z0-9]*(_[A-Z])?)*"), llvm::Regex("^[a-z]([a-z0-9]*(_[A-Z])?)*"), }; bool Matches = true; if (Name.startswith(Style.Prefix)) Name = Name.drop_front(Style.Prefix.size()); else Matches = false; if (Name.endswith(Style.Suffix)) Name = Name.drop_back(Style.Suffix.size()); else Matches = false; // Ensure the name doesn't have any extra underscores beyond those specified // in the prefix and suffix. if (Name.startswith("_") || Name.endswith("_")) Matches = false; if (Style.Case && !Matchers[static_cast<size_t>(*Style.Case)].match(Name)) Matches = false; return Matches; }
static bool matchesStyle(StringRef Name, IdentifierNamingCheck::NamingStyle Style) { static llvm::Regex Matchers[] = { llvm::Regex("^.*$"), llvm::Regex("^[a-z][a-z0-9_]*$"), llvm::Regex("^[a-z][a-zA-Z0-9]*$"), llvm::Regex("^[A-Z][A-Z0-9_]*$"), llvm::Regex("^[A-Z][a-zA-Z0-9]*$"), llvm::Regex("^[A-Z]([a-z0-9]*(_[A-Z])?)*"), llvm::Regex("^[a-z]([a-z0-9]*(_[A-Z])?)*"), }; bool Matches = true; if (Name.startswith(Style.Prefix)) Name = Name.drop_front(Style.Prefix.size()); else Matches = false; if (Name.endswith(Style.Suffix)) Name = Name.drop_back(Style.Suffix.size()); else Matches = false; if (!Matchers[static_cast<size_t>(Style.Case)].match(Name)) Matches = false; return Matches; }
static void WriteOutputFile(const Module *M) { // Infer the output filename if needed. if (OutputFilename.empty()) { if (InputFilename == "-") { OutputFilename = "-"; } else { StringRef IFN = InputFilename; OutputFilename = (IFN.endswith(".ll") ? IFN.drop_back(3) : IFN).str(); OutputFilename += ".bc"; } } std::error_code EC; std::unique_ptr<ToolOutputFile> Out( new ToolOutputFile(OutputFilename, EC, sys::fs::F_None)); if (EC) { errs() << EC.message() << '\n'; exit(1); } if (Force || !CheckBitcodeOutputToConsole(Out->os(), true)) WriteBitcodeToFile(*M, Out->os(), PreserveBitcodeUseListOrder, nullptr, EmitModuleHash); // Declare success. Out->keep(); }
int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); LLVMContext Context; llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. Context.setDiagnosticHandler(diagnosticHandler, argv[0]); cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n"); Expected<std::unique_ptr<Module>> MOrErr = openInputFile(Context); if (!MOrErr) { handleAllErrors(MOrErr.takeError(), [&](ErrorInfoBase &EIB) { errs() << argv[0] << ": "; EIB.log(errs()); errs() << '\n'; }); return 1; } std::unique_ptr<Module> M = std::move(*MOrErr); // Just use stdout. We won't actually print anything on it. if (DontPrint) OutputFilename = "-"; if (OutputFilename.empty()) { // Unspecified output, infer it. if (InputFilename == "-") { OutputFilename = "-"; } else { StringRef IFN = InputFilename; OutputFilename = (IFN.endswith(".bc") ? IFN.drop_back(3) : IFN).str(); OutputFilename += ".ll"; } } std::error_code EC; std::unique_ptr<tool_output_file> Out( new tool_output_file(OutputFilename, EC, sys::fs::F_None)); if (EC) { errs() << EC.message() << '\n'; return 1; } std::unique_ptr<AssemblyAnnotationWriter> Annotator; if (ShowAnnotations) Annotator.reset(new CommentWriter()); // All that llvm-dis does is write the assembly to a file. if (!DontPrint) M->print(Out->os(), Annotator.get(), PreserveAssemblyUseListOrder); // Declare success. Out->keep(); return 0; }
/// Returns the common word-prefix of two strings, allowing the second string /// to be a common English plural form of the first. /// /// For example, given "NSProperty" and "NSProperties", the full "NSProperty" /// is returned. Given "NSMagicArmor" and "NSMagicArmory", only /// "NSMagic" is returned. /// /// The "-s", "-es", and "-ies" patterns cover every plural NS_OPTIONS name /// in Cocoa and Cocoa Touch. /// /// \see getCommonWordPrefix StringRef importer::getCommonPluralPrefix(StringRef singular, StringRef plural) { assert(!plural.empty()); if (singular.empty()) return singular; bool ignored; StringRef commonPrefix = getCommonWordPrefix(singular, plural, ignored); if (commonPrefix.size() == singular.size() || plural.back() != 's') return commonPrefix; StringRef leftover = singular.substr(commonPrefix.size()); StringRef firstLeftoverWord = camel_case::getFirstWord(leftover); StringRef commonPrefixPlusWord = singular.substr(0, commonPrefix.size() + firstLeftoverWord.size()); // Is the plural string just "[singular]s"? plural = plural.drop_back(); if (plural.endswith(firstLeftoverWord)) return commonPrefixPlusWord; if (plural.empty() || plural.back() != 'e') return commonPrefix; // Is the plural string "[singular]es"? plural = plural.drop_back(); if (plural.endswith(firstLeftoverWord)) return commonPrefixPlusWord; if (plural.empty() || !(plural.back() == 'i' && singular.back() == 'y')) return commonPrefix; // Is the plural string "[prefix]ies" and the singular "[prefix]y"? plural = plural.drop_back(); firstLeftoverWord = firstLeftoverWord.drop_back(); if (plural.endswith(firstLeftoverWord)) return commonPrefixPlusWord; return commonPrefix; }
bool HasNameMatcher::matchesNodeFull(const NamedDecl &Node) const { llvm::SmallString<128> NodeName = StringRef("::"); llvm::raw_svector_ostream OS(NodeName); Node.printQualifiedName(OS); const StringRef FullName = OS.str(); const StringRef Pattern = Name; if (Pattern.startswith("::")) return FullName == Pattern; return FullName.endswith(Pattern) && FullName.drop_back(Pattern.size()).endswith("::"); }
// Makes a given pathname an absolute path first, and then remove // beginning /. For example, "../foo.o" is converted to "home/john/foo.o", // assuming that the current directory is "/home/john/bar". // Returned string is a forward slash separated path even on Windows to avoid // a mess with backslash-as-escape and backslash-as-path-separator. std::string lld::relativeToRoot(StringRef Path) { SmallString<128> Abs = Path; if (fs::make_absolute(Abs)) return Path; path::remove_dots(Abs, /*remove_dot_dot=*/true); // This is Windows specific. root_name() returns a drive letter // (e.g. "c:") or a UNC name (//net). We want to keep it as part // of the result. SmallString<128> Res; StringRef Root = path::root_name(Abs); if (Root.endswith(":")) Res = Root.drop_back(); else if (Root.startswith("//")) Res = Root.substr(2); path::append(Res, path::relative_path(Abs)); return path::convert_to_slash(Res); }
static void WriteOutputFile(const Module *M, const ModuleSummaryIndex *Index) { // Infer the output filename if needed. if (OutputFilename.empty()) { if (InputFilename == "-") { OutputFilename = "-"; } else { StringRef IFN = InputFilename; OutputFilename = (IFN.endswith(".ll") ? IFN.drop_back(3) : IFN).str(); OutputFilename += ".bc"; } } std::error_code EC; std::unique_ptr<ToolOutputFile> Out( new ToolOutputFile(OutputFilename, EC, sys::fs::F_None)); if (EC) { errs() << EC.message() << '\n'; exit(1); } if (Force || !CheckBitcodeOutputToConsole(Out->os(), true)) { const ModuleSummaryIndex *IndexToWrite = nullptr; // Don't attempt to write a summary index unless it contains any entries. // Otherwise we get an empty summary section. if (Index && Index->begin() != Index->end()) IndexToWrite = Index; if (!IndexToWrite || (M && (!M->empty() || !M->global_empty()))) // If we have a non-empty Module, then we write the Module plus // any non-null Index along with it as a per-module Index. // If both are empty, this will give an empty module block, which is // the expected behavior. WriteBitcodeToFile(*M, Out->os(), PreserveBitcodeUseListOrder, IndexToWrite, EmitModuleHash); else // Otherwise, with an empty Module but non-empty Index, we write a // combined index. WriteIndexToFile(*IndexToWrite, Out->os()); } // Declare success. Out->keep(); }
bool MSP430AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { // Drop .w suffix if (Name.endswith_lower(".w")) Name = Name.drop_back(2); if (!parseJccInstruction(Info, Name, NameLoc, Operands)) return false; // First operand is instruction mnemonic Operands.push_back(MSP430Operand::CreateToken(Name, NameLoc)); // If there are no more operands, then finish if (getLexer().is(AsmToken::EndOfStatement)) return false; // Parse first operand if (ParseOperand(Operands)) return true; // Parse second operand if any if (getLexer().is(AsmToken::Comma)) { getLexer().Lex(); // Eat ',' if (ParseOperand(Operands)) return true; } if (getLexer().isNot(AsmToken::EndOfStatement)) { SMLoc Loc = getLexer().getLoc(); getParser().eatToEndOfStatement(); return Error(Loc, "unexpected token"); } getParser().Lex(); // Consume the EndOfStatement. return false; }
static bool MacroBodyEndsInBackslash(StringRef MacroBody) { while (!MacroBody.empty() && isWhitespace(MacroBody.back())) MacroBody = MacroBody.drop_back(); return !MacroBody.empty() && MacroBody.back() == '\\'; }
IAMResult IAMInference::infer(const clang::NamedDecl *clangDecl) { if (clangDecl->getName().startswith("_")) { ++SkipLeadingUnderscore; return {}; } // Try to infer a member variable if (auto varDecl = dyn_cast<clang::VarDecl>(clangDecl)) return inferVar(varDecl); // Try to infer a member function auto funcDecl = dyn_cast<clang::FunctionDecl>(clangDecl); if (!funcDecl) { // TODO: Do we want to collects stats here? Should it be assert? return {}; } auto fail = [funcDecl]() -> IAMResult { DEBUG(llvm::dbgs() << "failed to infer function: "); DEBUG(funcDecl->print(llvm::dbgs())); DEBUG(llvm::dbgs() << "\n"); ++FailInferFunction; return {}; }; // Can't really import variadics well if (funcDecl->isVariadic()) return fail(); // FIXME: drop "Mutable"... StringRef workingName = funcDecl->getName(); auto retTy = funcDecl->getReturnType(); unsigned numParams = funcDecl->getNumParams(); // 0) Special cases are specially handled // StringRef getTypeID = "GetTypeID"; StringRef cfSpecials[] = {"Release", "Retain", "Autorelease"}; // *GetTypeID if (numParams == 0 && workingName.endswith(getTypeID)) { NameBuffer remainingName; if (auto effectiveDC = findTypeAndMatch( workingName.drop_back(getTypeID.size()), remainingName)) { // We shouldn't have anything else left in our name for typeID if (remainingName.empty()) { return importAsTypeID(retTy, effectiveDC); } } // *Release/*Retain/*Autorelease } else if (numParams == 1 && std::any_of(std::begin(cfSpecials), std::end(cfSpecials), [workingName](StringRef suffix) { return workingName.endswith(suffix); })) { if (auto type = funcDecl->getParamDecl(0)->getType()->getAs<clang::TypedefType>()) { if (CFPointeeInfo::classifyTypedef(type->getDecl())) { ++SkipCFMemoryManagement; return {}; } } } // 1) If we find an init specifier and our name matches the return type, we // import as some kind of constructor // if (!retTy->isVoidType()) { NameBuffer remainingName; if (matchTypeName(workingName, retTy, remainingName)) for (auto initSpec : InitSpecifiers) if (hasWord(remainingName, initSpec)) if (auto effectiveDC = getEffectiveDC(retTy)) return importAsConstructor( remainingName, initSpec, {funcDecl->param_begin(), funcDecl->param_end()}, effectiveDC); } // 2) If we find a likely self reference in the parameters, make an instance // member (method or property) // SmallVector<const clang::ParmVarDecl *, 8> nonSelfParams; unsigned selfIdx = 0; for (auto paramI = funcDecl->param_begin(), paramE = funcDecl->param_end(); paramI != paramE; ++paramI, ++selfIdx) { auto param = *paramI; NameBuffer remainingName; if (matchTypeName(workingName, param->getType(), remainingName)) { auto effectiveDC = getEffectiveDC(param->getType()); if (!effectiveDC) continue; nonSelfParams.append(funcDecl->param_begin(), paramI); nonSelfParams.append(++paramI, paramE); // See if it's a property for (auto propSpec : PropertySpecifiers) { NameBuffer propName; if (match(remainingName, propSpec, propName)) { const clang::FunctionDecl *pairedAccessor; if (validToImportAsProperty(funcDecl, propSpec, selfIdx, pairedAccessor)) return importAsInstanceProperty(propName, propSpec, selfIdx, nonSelfParams, pairedAccessor, effectiveDC); } } return importAsInstanceMethod(remainingName, selfIdx, nonSelfParams, effectiveDC); } } // No self, must be static nonSelfParams = {funcDecl->param_begin(), funcDecl->param_end()}; // 3) Finally, try to find a class to put this on as a static function NameBuffer remainingName; if (auto effectiveDC = findTypeAndMatch(workingName, remainingName)) { ArrayRef<const clang::ParmVarDecl *> params = {funcDecl->param_begin(), funcDecl->param_end()}; // See if it's a property for (auto propSpec : PropertySpecifiers) { NameBuffer propName; if (match(remainingName, propSpec, propName)) { const clang::FunctionDecl *pairedAccessor; if (validToImportAsProperty(funcDecl, propSpec, None, pairedAccessor)) return importAsStaticProperty(propName, propSpec, nonSelfParams, pairedAccessor, effectiveDC); } } StringRef methodName = remainingName == "" ? workingName : StringRef(remainingName); return importAsStaticMethod(methodName, nonSelfParams, effectiveDC); } return fail(); }
/// Return the name to import a CF typedef as. static StringRef getImportedCFTypeName(StringRef name) { // If the name ends in the CF typedef suffix ("Ref"), drop that. if (name.endswith(SWIFT_CFTYPE_SUFFIX)) return name.drop_back(strlen(SWIFT_CFTYPE_SUFFIX)); return name; }
static MCSymbol *smallData(AsmPrinter &AP, const MachineInstr &MI, MCStreamer &OutStreamer, const MCOperand &Imm, int AlignSize) { MCSymbol *Sym; int64_t Value; if (Imm.getExpr()->evaluateAsAbsolute(Value)) { StringRef sectionPrefix; std::string ImmString; StringRef Name; if (AlignSize == 8) { Name = ".CONST_0000000000000000"; sectionPrefix = ".gnu.linkonce.l8"; ImmString = utohexstr(Value); } else { Name = ".CONST_00000000"; sectionPrefix = ".gnu.linkonce.l4"; ImmString = utohexstr(static_cast<uint32_t>(Value)); } std::string symbolName = // Yes, leading zeros are kept. Name.drop_back(ImmString.size()).str() + ImmString; std::string sectionName = sectionPrefix.str() + symbolName; MCSectionELF *Section = OutStreamer.getContext().getELFSection( sectionName, ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); OutStreamer.SwitchSection(Section); Sym = AP.OutContext.getOrCreateSymbol(Twine(symbolName)); if (Sym->isUndefined()) { OutStreamer.EmitLabel(Sym); OutStreamer.EmitSymbolAttribute(Sym, MCSA_Global); OutStreamer.EmitIntValue(Value, AlignSize); OutStreamer.EmitCodeAlignment(AlignSize); } } else { assert(Imm.isExpr() && "Expected expression and found none"); const MachineOperand &MO = MI.getOperand(1); assert(MO.isGlobal() || MO.isCPI() || MO.isJTI()); MCSymbol *MOSymbol = nullptr; if (MO.isGlobal()) MOSymbol = AP.getSymbol(MO.getGlobal()); else if (MO.isCPI()) MOSymbol = AP.GetCPISymbol(MO.getIndex()); else if (MO.isJTI()) MOSymbol = AP.GetJTISymbol(MO.getIndex()); else llvm_unreachable("Unknown operand type!"); StringRef SymbolName = MOSymbol->getName(); std::string LitaName = ".CONST_" + SymbolName.str(); MCSectionELF *Section = OutStreamer.getContext().getELFSection( ".lita", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); OutStreamer.SwitchSection(Section); Sym = AP.OutContext.getOrCreateSymbol(Twine(LitaName)); if (Sym->isUndefined()) { OutStreamer.EmitLabel(Sym); OutStreamer.EmitSymbolAttribute(Sym, MCSA_Local); OutStreamer.EmitValue(Imm.getExpr(), AlignSize); OutStreamer.EmitCodeAlignment(AlignSize); } } return Sym; }
int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. Context.setDiagnosticHandler(diagnosticHandler, argv[0]); cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n"); std::string ErrorMessage; std::unique_ptr<Module> M; // Use the bitcode streaming interface DataStreamer *Streamer = getDataFileStreamer(InputFilename, &ErrorMessage); if (Streamer) { std::string DisplayFilename; if (InputFilename == "-") DisplayFilename = "<stdin>"; else DisplayFilename = InputFilename; ErrorOr<std::unique_ptr<Module>> MOrErr = getStreamedBitcodeModule(DisplayFilename, Streamer, Context); M = std::move(*MOrErr); M->materializeAllPermanently(); } else { errs() << argv[0] << ": " << ErrorMessage << '\n'; return 1; } // Just use stdout. We won't actually print anything on it. if (DontPrint) OutputFilename = "-"; if (OutputFilename.empty()) { // Unspecified output, infer it. if (InputFilename == "-") { OutputFilename = "-"; } else { StringRef IFN = InputFilename; OutputFilename = (IFN.endswith(".bc") ? IFN.drop_back(3) : IFN).str(); OutputFilename += ".ll"; } } std::error_code EC; std::unique_ptr<tool_output_file> Out( new tool_output_file(OutputFilename, EC, sys::fs::F_None)); if (EC) { errs() << EC.message() << '\n'; return 1; } std::unique_ptr<AssemblyAnnotationWriter> Annotator; if (ShowAnnotations) Annotator.reset(new CommentWriter()); // All that llvm-dis does is write the assembly to a file. if (!DontPrint) M->print(Out->os(), Annotator.get(), PreserveAssemblyUseListOrder); // Declare success. Out->keep(); return 0; }
static bool hasPrefix(StringRef SectionName, StringRef Prefix) { return SectionName.startswith(Prefix) || SectionName == Prefix.drop_back(); }
IAMResult IAMInference::infer(const clang::NamedDecl *clangDecl) { if (clangDecl->getName().startswith("_")) { ++SkipLeadingUnderscore; return {}; } if (auto varDecl = dyn_cast<clang::VarDecl>(clangDecl)) { auto fail = [varDecl]() -> IAMResult { DEBUG(llvm::dbgs() << "failed to infer variable: "); DEBUG(varDecl->print(llvm::dbgs())); DEBUG(llvm::dbgs() << "\n"); ++FailInferVar; return {}; }; // Try to find a type to add this as a static property to StringRef workingName = varDecl->getName(); if (workingName.empty()) return fail(); // Special pattern: constants of the form "kFooBarBaz", extend "FooBar" with // property "Baz" if (*camel_case::getWords(workingName).begin() == "k") workingName = workingName.drop_front(1); NameBuffer remainingName; if (auto effectiveDC = findTypeAndMatch(workingName, remainingName)) return importAsStaticProperty(remainingName, effectiveDC); return fail(); } // Try to infer a member function auto funcDecl = dyn_cast<clang::FunctionDecl>(clangDecl); if (!funcDecl) { // TODO: Do we want to collects stats here? Should it be assert? return {}; } auto fail = [funcDecl]() -> IAMResult { DEBUG(llvm::dbgs() << "failed to infer function: "); DEBUG(funcDecl->print(llvm::dbgs())); DEBUG(llvm::dbgs() << "\n"); ++FailInferFunction; return {}; }; // Can't really import variadics well if (funcDecl->isVariadic()) return fail(); // FIXME: drop "Mutable"... StringRef workingName = funcDecl->getName(); auto retTy = funcDecl->getReturnType(); unsigned numParams = funcDecl->getNumParams(); // 0) Special cases are specially handled: *GetTypeID() // StringRef getTypeID = "GetTypeID"; if (numParams == 0 && workingName.endswith(getTypeID)) { NameBuffer remainingName; if (auto effectiveDC = findTypeAndMatch( workingName.drop_back(getTypeID.size()), remainingName)) { // We shouldn't have anything else left in our name for typeID if (remainingName.empty()) { return importAsTypeID(retTy, effectiveDC); } } } // 1) If we find an init specifier and our name matches the return type, we // import as some kind of constructor // if (!retTy->isVoidType()) { NameBuffer remainingName; if (matchTypeName(workingName, retTy, remainingName)) for (auto initSpec : InitSpecifiers) if (hasWord(remainingName, initSpec)) if (auto effectiveDC = getEffectiveDC(retTy)) return importAsConstructor( remainingName, initSpec, {funcDecl->param_begin(), funcDecl->param_end()}, effectiveDC); } // 2) If we find a likely self reference in the parameters, make an instance // member (method or property) // SmallVector<const clang::ParmVarDecl *, 8> nonSelfParams; unsigned selfIdx = 0; for (auto paramI = funcDecl->param_begin(), paramE = funcDecl->param_end(); paramI != paramE; ++paramI, ++selfIdx) { auto param = *paramI; NameBuffer remainingName; if (matchTypeName(workingName, param->getType(), remainingName)) { auto effectiveDC = getEffectiveDC(param->getType()); if (!effectiveDC) continue; nonSelfParams.append(funcDecl->param_begin(), paramI); nonSelfParams.append(++paramI, paramE); // See if it's a property for (auto propSpec : PropertySpecifiers) { NameBuffer propName; if (match(remainingName, propSpec, propName)) { const clang::FunctionDecl *pairedAccessor; if (validToImportAsProperty(funcDecl, propSpec, selfIdx, pairedAccessor)) return importAsInstanceProperty(propName, propSpec, selfIdx, nonSelfParams, pairedAccessor, effectiveDC); } } return importAsInstanceMethod(remainingName, selfIdx, nonSelfParams, effectiveDC); } } // No self, must be static nonSelfParams = {funcDecl->param_begin(), funcDecl->param_end()}; // 3) Finally, try to find a class to put this on as a static function NameBuffer remainingName; if (auto effectiveDC = findTypeAndMatch(workingName, remainingName)) { ArrayRef<const clang::ParmVarDecl *> params = {funcDecl->param_begin(), funcDecl->param_end()}; // See if it's a property for (auto propSpec : PropertySpecifiers) { NameBuffer propName; if (match(remainingName, propSpec, propName)) { const clang::FunctionDecl *pairedAccessor; if (validToImportAsProperty(funcDecl, propSpec, None, pairedAccessor)) return importAsStaticProperty(propName, propSpec, nonSelfParams, pairedAccessor, effectiveDC); } } return importAsStaticMethod(remainingName, nonSelfParams, effectiveDC); } return fail(); }
static std::unique_ptr<tool_output_file> GetOutputStream(const char *TargetName, Triple::OSType OS, const char *ProgName) { // If we don't yet have an output filename, make one. if (OutputFilename.empty()) { if (InputFilename == "-") OutputFilename = "-"; else { // If InputFilename ends in .bc or .ll, remove it. StringRef IFN = InputFilename; if (IFN.endswith(".bc") || IFN.endswith(".ll")) OutputFilename = IFN.drop_back(3); else OutputFilename = IFN; switch (FileType) { case TargetMachine::CGFT_AssemblyFile: if (TargetName[0] == 'c') { if (TargetName[1] == 0) OutputFilename += ".cbe.c"; else if (TargetName[1] == 'p' && TargetName[2] == 'p') OutputFilename += ".cpp"; else OutputFilename += ".s"; } else OutputFilename += ".s"; break; case TargetMachine::CGFT_ObjectFile: if (OS == Triple::Win32) OutputFilename += ".obj"; else OutputFilename += ".o"; break; case TargetMachine::CGFT_Null: OutputFilename += ".null"; break; } } } // Decide if we need "binary" output. bool Binary = false; switch (FileType) { case TargetMachine::CGFT_AssemblyFile: break; case TargetMachine::CGFT_ObjectFile: case TargetMachine::CGFT_Null: Binary = true; break; } // Open the file. std::error_code EC; sys::fs::OpenFlags OpenFlags = sys::fs::F_None; if (!Binary) OpenFlags |= sys::fs::F_Text; auto FDOut = llvm::make_unique<tool_output_file>(OutputFilename, EC, OpenFlags); if (EC) { errs() << EC.message() << '\n'; return nullptr; } return FDOut; }
LineList MarkupContext::getLineList(swift::RawComment RC) { LineListBuilder Builder(*this); for (const auto &C : RC.Comments) { if (C.isLine()) { // Skip comment marker. unsigned CommentMarkerBytes = 2 + (C.isOrdinary() ? 0 : 1); StringRef Cleaned = C.RawText.drop_front(CommentMarkerBytes); // Drop trailing newline. Cleaned = Cleaned.rtrim("\n\r"); auto CleanedStartLoc = C.Range.getStart().getAdvancedLocOrInvalid(CommentMarkerBytes); auto CleanedEndLoc = C.Range.getStart().getAdvancedLocOrInvalid(Cleaned.size()); Builder.addLine(Cleaned, { CleanedStartLoc, CleanedEndLoc }); } else { // Skip comment markers at the beginning and at the end. unsigned CommentMarkerBytes = 2 + (C.isOrdinary() ? 0 : 1); StringRef Cleaned = C.RawText.drop_front(CommentMarkerBytes); if (Cleaned.endswith("*/")) Cleaned = Cleaned.drop_back(2); else if (Cleaned.endswith("/")) Cleaned = Cleaned.drop_back(1); swift::SourceLoc CleanedStartLoc = C.Range.getStart().getAdvancedLocOrInvalid(CommentMarkerBytes); // Determine if we have leading decorations in this block comment. bool HasASCIIArt = false; if (swift::startsWithNewline(Cleaned)) { Builder.addLine(Cleaned.substr(0, 0), { C.Range.getStart(), C.Range.getStart() }); unsigned NewlineBytes = swift::measureNewline(Cleaned); Cleaned = Cleaned.drop_front(NewlineBytes); CleanedStartLoc = CleanedStartLoc.getAdvancedLocOrInvalid(NewlineBytes); HasASCIIArt = measureASCIIArt(Cleaned, C.StartColumn - 1) != 0; } while (!Cleaned.empty()) { size_t Pos = Cleaned.find_first_of("\n\r"); if (Pos == StringRef::npos) Pos = Cleaned.size(); // Skip over ASCII art, if present. if (HasASCIIArt) if (unsigned ASCIIArtBytes = measureASCIIArt(Cleaned, C.StartColumn - 1)) { Cleaned = Cleaned.drop_front(ASCIIArtBytes); CleanedStartLoc = CleanedStartLoc.getAdvancedLocOrInvalid(ASCIIArtBytes); Pos -= ASCIIArtBytes; } StringRef Line = Cleaned.substr(0, Pos); auto CleanedEndLoc = CleanedStartLoc.getAdvancedLocOrInvalid(Pos); Cleaned = Cleaned.drop_front(Pos); unsigned NewlineBytes = swift::measureNewline(Cleaned); Cleaned = Cleaned.drop_front(NewlineBytes); Pos += NewlineBytes; CleanedStartLoc = CleanedStartLoc.getAdvancedLocOrInvalid(Pos); Builder.addLine(Line, { CleanedStartLoc, CleanedEndLoc }); } } } return Builder.takeLineList(); }