void writeSymbol(const Symbol &Sym, const StringTableOut &Strings, llvm::raw_ostream &OS) { OS << Sym.ID.raw(); // TODO: once we start writing xrefs and posting lists, // symbol IDs should probably be in a string table. OS.write(static_cast<uint8_t>(Sym.SymInfo.Kind)); OS.write(static_cast<uint8_t>(Sym.SymInfo.Lang)); writeVar(Strings.index(Sym.Name), OS); writeVar(Strings.index(Sym.Scope), OS); writeVar(Strings.index(Sym.TemplateSpecializationArgs), OS); writeLocation(Sym.Definition, Strings, OS); writeLocation(Sym.CanonicalDeclaration, Strings, OS); writeVar(Sym.References, OS); OS.write(static_cast<uint8_t>(Sym.Flags)); OS.write(static_cast<uint8_t>(Sym.Origin)); writeVar(Strings.index(Sym.Signature), OS); writeVar(Strings.index(Sym.CompletionSnippetSuffix), OS); writeVar(Strings.index(Sym.Documentation), OS); writeVar(Strings.index(Sym.ReturnType), OS); writeVar(Strings.index(Sym.Type), OS); auto WriteInclude = [&](const Symbol::IncludeHeaderWithReferences &Include) { writeVar(Strings.index(Include.IncludeHeader), OS); writeVar(Include.References, OS); }; writeVar(Sym.IncludeHeaders.size(), OS); for (const auto &Include : Sym.IncludeHeaders) WriteInclude(Include); }
/// \brief Format the given diagnostic text and place the result in the given /// buffer. static void formatDiagnosticText(StringRef InText, ArrayRef<DiagnosticArgument> Args, llvm::raw_ostream &Out) { while (!InText.empty()) { size_t Percent = InText.find('%'); if (Percent == StringRef::npos) { // Write the rest of the string; we're done. Out.write(InText.data(), InText.size()); break; } // Write the string up to (but not including) the %, then drop that text // (including the %). Out.write(InText.data(), Percent); InText = InText.substr(Percent + 1); // '%%' -> '%'. if (InText[0] == '%') { Out.write('%'); InText = InText.substr(1); continue; } // Parse an optional modifier. StringRef Modifier; { unsigned Length = 0; while (isalpha(InText[Length])) ++Length; Modifier = InText.substr(0, Length); InText = InText.substr(Length); } // Parse the optional argument list for a modifier, which is brace-enclosed. StringRef ModifierArguments; if (InText[0] == '{') { InText = InText.substr(1); ModifierArguments = skipToDelimiter(InText, '}'); } // Find the digit sequence. unsigned Length = 0; for (size_t N = InText.size(); Length != N; ++Length) { if (!isdigit(InText[Length])) break; } // Parse the digit sequence into an argument index. unsigned ArgIndex; bool Result = InText.substr(0, Length).getAsInteger(10, ArgIndex); assert(!Result && "Unparseable argument index value?"); (void)Result; assert(ArgIndex < Args.size() && "Out-of-range argument index"); InText = InText.substr(Length); // Convert the argument to a string. formatDiagnosticArgument(Modifier, ModifierArguments, Args, ArgIndex, Out); } }
void writeRefs(const SymbolID &ID, llvm::ArrayRef<Ref> Refs, const StringTableOut &Strings, llvm::raw_ostream &OS) { OS << ID.raw(); writeVar(Refs.size(), OS); for (const auto &Ref : Refs) { OS.write(static_cast<unsigned char>(Ref.Kind)); writeLocation(Ref.Location, Strings, OS); } }
void writeIncludeGraphNode(const IncludeGraphNode &IGN, const StringTableOut &Strings, llvm::raw_ostream &OS) { OS.write(IGN.IsTU); writeVar(Strings.index(IGN.URI), OS); llvm::StringRef Hash(reinterpret_cast<const char *>(IGN.Digest.data()), IGN.Digest.size()); OS << Hash; writeVar(IGN.DirectIncludes.size(), OS); for (llvm::StringRef Include : IGN.DirectIncludes) writeVar(Strings.index(Include), OS); }
bool ASTUnit::serialize(llvm::raw_ostream &OS) { if (getDiagnostics().hasErrorOccurred()) return true; SmallString<128> Buffer; llvm::BitstreamWriter Stream(Buffer); ASTWriter Writer(Stream); Writer.WriteAST(getSema(), 0, std::string(), 0); // Write the generated bitstream to "Out". if (!Buffer.empty()) OS.write((char *)&Buffer.front(), Buffer.size()); return false; }
/// Writes the code completion results from the sink for \p V to \p out. /// /// The high-level format is: /// /// HEADER /// * version, which **must be bumped** if we change the format! /// * mtime for the module file /// /// KEY /// * the original CodeCompletionCache::Key, used for debugging the cache. /// /// RESULTS /// * A length-prefixed array of fixed size CodeCompletionResults. /// * Contains offsets into CHUNKS and STRINGS. /// /// CHUNKS /// * A length-prefixed array of CodeCompletionStrings. /// * Each CodeCompletionString is a length-prefixed array of fixed size /// CodeCompletionString::Chunks. /// /// STRINGS /// * A blob of length-prefixed strings referred to in CHUNKS or RESULTS. static void writeCachedModule(llvm::raw_ostream &out, const CodeCompletionCache::Key &K, CodeCompletionCache::Value &V) { using namespace llvm::support; endian::Writer LE(out, little); // HEADER // Metadata required for reading the completions. LE.write(onDiskCompletionCacheVersion); // Version auto mtime = V.ModuleModificationTime.time_since_epoch().count(); LE.write(mtime); // Mtime for module file // KEY // We don't need the stored key to load the results, but it is useful if we // want to debug the cache itself. { SmallString<256> scratch; llvm::raw_svector_ostream OSS(scratch); OSS << K.ModuleFilename << "\0"; OSS << K.ModuleName << "\0"; endian::Writer OSSLE(OSS, little); OSSLE.write(K.AccessPath.size()); for (StringRef p : K.AccessPath) OSS << p << "\0"; OSSLE.write(K.ResultsHaveLeadingDot); OSSLE.write(K.ForTestableLookup); OSSLE.write(K.ForPrivateImportLookup); OSSLE.write(K.CodeCompleteInitsInPostfixExpr); LE.write(static_cast<uint32_t>(OSS.tell())); // Size of debug info out.write(OSS.str().data(), OSS.str().size()); // Debug info blob } // String streams for writing to the CHUNKS and STRINGS sections. std::string results_; llvm::raw_string_ostream results(results_); std::string chunks_; llvm::raw_string_ostream chunks(chunks_); endian::Writer chunksLE(chunks, little); std::string strings_; llvm::raw_string_ostream strings(strings_); auto addString = [&strings](StringRef str) { if (str.empty()) return ~0u; auto size = strings.tell(); endian::Writer LE(strings, little); LE.write(static_cast<uint32_t>(str.size())); strings << str; return static_cast<uint32_t>(size); }; auto addCompletionString = [&](const CodeCompletionString *str) { auto size = chunks.tell(); chunksLE.write(static_cast<uint32_t>(str->getChunks().size())); for (auto chunk : str->getChunks()) { chunksLE.write(static_cast<uint8_t>(chunk.getKind())); chunksLE.write(static_cast<uint8_t>(chunk.getNestingLevel())); chunksLE.write(static_cast<uint8_t>(chunk.isAnnotation())); if (chunk.hasText()) { chunksLE.write(addString(chunk.getText())); } else { chunksLE.write(static_cast<uint32_t>(~0u)); } } return static_cast<uint32_t>(size); }; // RESULTS { endian::Writer LE(results, little); for (CodeCompletionResult *R : V.Sink.Results) { // FIXME: compress bitfield LE.write(static_cast<uint8_t>(R->getKind())); if (R->getKind() == CodeCompletionResult::Declaration) LE.write(static_cast<uint8_t>(R->getAssociatedDeclKind())); else LE.write(~static_cast<uint8_t>(0u)); if (R->isOperator()) LE.write(static_cast<uint8_t>(R->getOperatorKind())); else LE.write(static_cast<uint8_t>(CodeCompletionOperatorKind::None)); LE.write(static_cast<uint8_t>(R->getSemanticContext())); LE.write(static_cast<uint8_t>(R->isNotRecommended())); LE.write(static_cast<uint8_t>(R->getNumBytesToErase())); LE.write( static_cast<uint32_t>(addCompletionString(R->getCompletionString()))); LE.write(addString(R->getModuleName())); // index into strings LE.write(addString(R->getBriefDocComment())); // index into strings LE.write(static_cast<uint32_t>(R->getAssociatedUSRs().size())); if (R->getAssociatedUSRs().empty()) { LE.write(static_cast<uint32_t>(~0u)); } else { LE.write(addString(R->getAssociatedUSRs()[0])); for (unsigned i = 1; i < R->getAssociatedUSRs().size(); ++i) { addString(R->getAssociatedUSRs()[i]); // ignore result } } auto AllKeywords = R->getDeclKeywords(); LE.write(static_cast<uint32_t>(AllKeywords.size())); if (AllKeywords.empty()) { LE.write(static_cast<uint32_t>(~0u)); } else { LE.write(addString(AllKeywords[0].first)); addString(AllKeywords[0].second); for (unsigned i = 1; i < AllKeywords.size(); ++i) { addString(AllKeywords[i].first); addString(AllKeywords[i].second); } } } } LE.write(static_cast<uint32_t>(results.tell())); out << results.str(); // CHUNKS LE.write(static_cast<uint32_t>(chunks.tell())); out << chunks.str(); // STRINGS LE.write(static_cast<uint32_t>(strings.tell())); out << strings.str(); }
/// \brief Print the given string to a stream, word-wrapping it to /// some number of columns in the process. /// /// \brief OS the stream to which the word-wrapping string will be /// emitted. /// /// \brief Str the string to word-wrap and output. /// /// \brief Columns the number of columns to word-wrap to. /// /// \brief Column the column number at which the first character of \p /// Str will be printed. This will be non-zero when part of the first /// line has already been printed. /// /// \brief Indentation the number of spaces to indent any lines beyond /// the first line. /// /// \returns true if word-wrapping was required, or false if the /// string fit on the first line. static bool PrintWordWrapped(llvm::raw_ostream &OS, const llvm::SmallVectorImpl<char> &Str, unsigned Columns, unsigned Column = 0, unsigned Indentation = WordWrapIndentation) { unsigned Length = Str.size(); // If there is a newline in this message somewhere, find that // newline and split the message into the part before the newline // (which will be word-wrapped) and the part from the newline one // (which will be emitted unchanged). for (unsigned I = 0; I != Length; ++I) if (Str[I] == '\n') { Length = I; break; } // The string used to indent each line. llvm::SmallString<16> IndentStr; IndentStr.assign(Indentation, ' '); bool Wrapped = false; for (unsigned WordStart = 0, WordEnd; WordStart < Length; WordStart = WordEnd) { // Find the beginning of the next word. WordStart = skipWhitespace(WordStart, Str, Length); if (WordStart == Length) break; // Find the end of this word. WordEnd = findEndOfWord(WordStart, Str, Length, Column, Columns); // Does this word fit on the current line? unsigned WordLength = WordEnd - WordStart; if (Column + WordLength < Columns) { // This word fits on the current line; print it there. if (WordStart) { OS << ' '; Column += 1; } OS.write(&Str[WordStart], WordLength); Column += WordLength; continue; } // This word does not fit on the current line, so wrap to the next // line. OS << '\n'; OS.write(&IndentStr[0], Indentation); OS.write(&Str[WordStart], WordLength); Column = Indentation + WordLength; Wrapped = true; } if (Length == Str.size()) return Wrapped; // We're done. // There is a newline in the message, followed by something that // will not be word-wrapped. Print that. OS.write(&Str[Length], Str.size() - Length); return true; }
static void WriteString(llvm::raw_ostream &OS, llvm::StringRef String) { WriteUnsigned(OS, String.size()); OS.write(String.data(), String.size()); }
static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) { OS.write((const char *)&Value, sizeof(unsigned)); }
/// Finish the mangling of the symbol and write the mangled name into /// \p stream. void Mangler::finalize(llvm::raw_ostream &stream) { std::string result = finalize(); stream.write(result.data(), result.size()); }