owenv updated this revision to Diff 265592. owenv added a comment. - Update a few comments - Simplify test case
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D80126/new/ https://reviews.llvm.org/D80126 Files: clang/include/clang-c/Index.h clang/include/clang/Frontend/SerializedDiagnosticReader.h clang/include/clang/Frontend/SerializedDiagnostics.h clang/lib/Frontend/SerializedDiagnosticPrinter.cpp clang/lib/Frontend/SerializedDiagnosticReader.cpp clang/test/Misc/Inputs/serialized-diags-documentation.dia clang/test/Misc/serialized-diags-documentation.c clang/tools/c-index-test/c-index-test.c clang/tools/libclang/CIndexDiagnostic.cpp clang/tools/libclang/CIndexDiagnostic.h clang/tools/libclang/CXLoadedDiagnostic.cpp clang/tools/libclang/CXLoadedDiagnostic.h clang/tools/libclang/CXStoredDiagnostic.cpp clang/tools/libclang/libclang.exports
Index: clang/tools/libclang/libclang.exports =================================================================== --- clang/tools/libclang/libclang.exports +++ clang/tools/libclang/libclang.exports @@ -219,6 +219,7 @@ clang_getDiagnosticCategory clang_getDiagnosticCategoryName clang_getDiagnosticCategoryText +clang_getDiagnosticDocumentationURLs clang_getDiagnosticFixIt clang_getDiagnosticInSet clang_getDiagnosticLocation Index: clang/tools/libclang/CXStoredDiagnostic.cpp =================================================================== --- clang/tools/libclang/CXStoredDiagnostic.cpp +++ clang/tools/libclang/CXStoredDiagnostic.cpp @@ -109,3 +109,7 @@ return cxstring::createDup(Hint.CodeToInsert); } +CXStringSet *CXStoredDiagnostic::getDocumentationURLs() const { + // Documentation URLs are not yet implemented for native Clang diagnostics. + return cxstring::createSet({}); +} Index: clang/tools/libclang/CXLoadedDiagnostic.h =================================================================== --- clang/tools/libclang/CXLoadedDiagnostic.h +++ clang/tools/libclang/CXLoadedDiagnostic.h @@ -58,6 +58,9 @@ CXString getFixIt(unsigned FixIt, CXSourceRange *ReplacementRange) const override; + /// Return the documentation URLs associated with the diagnostic. + virtual CXStringSet *getDocumentationURLs() const override; + static bool classof(const CXDiagnosticImpl *D) { return D->getKind() == LoadedDiagnosticKind; } @@ -82,6 +85,7 @@ std::vector<CXSourceRange> Ranges; std::vector<std::pair<CXSourceRange, const char *> > FixIts; + std::vector<std::string> DocumentationURLs; const char *Spelling; llvm::StringRef DiagOption; llvm::StringRef CategoryText; Index: clang/tools/libclang/CXLoadedDiagnostic.cpp =================================================================== --- clang/tools/libclang/CXLoadedDiagnostic.cpp +++ clang/tools/libclang/CXLoadedDiagnostic.cpp @@ -41,7 +41,8 @@ Strings Categories; Strings WarningFlags; Strings FileNames; - + Strings DocumentationURLs; + FileSystemOptions FO; FileManager FakeFiles; llvm::DenseMap<unsigned, const FileEntry *> Files; @@ -145,6 +146,10 @@ return cxstring::createRef(FixIts[FixIt].second); } +CXStringSet *CXLoadedDiagnostic::getDocumentationURLs() const { + return cxstring::createSet(DocumentationURLs); +} + void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location, CXFile *file, unsigned int *line, @@ -233,6 +238,10 @@ visitSourceRangeRecord(const serialized_diags::Location &Start, const serialized_diags::Location &End) override; + std::error_code visitDocumentationURLRecord(unsigned ID, + StringRef Path) override; + std::error_code visitDocumentationRecord(unsigned ID) override; + public: DiagLoader(enum CXLoadDiag_Error *e, CXString *es) : SerializedDiagnosticReader(), error(e), errorString(es) { @@ -347,6 +356,15 @@ return std::error_code(); } +std::error_code DiagLoader::visitDocumentationURLRecord(unsigned ID, + StringRef Path) { + // FIXME: Why do we care about long strings? + if (Path.size() > 65536) + return reportInvalidFile("Out-of-bounds string in documentation URL."); + TopDiags->DocumentationURLs[ID] = TopDiags->copyString(Path); + return std::error_code(); +} + std::error_code DiagLoader::visitSourceRangeRecord(const serialized_diags::Location &Start, const serialized_diags::Location &End) { @@ -372,6 +390,12 @@ return std::error_code(); } +std::error_code DiagLoader::visitDocumentationRecord(unsigned ID) { + CurrentDiags.back()->DocumentationURLs.push_back( + TopDiags->DocumentationURLs[ID]); + return std::error_code(); +} + std::error_code DiagLoader::visitDiagnosticRecord( unsigned Severity, const serialized_diags::Location &Location, unsigned Category, unsigned Flag, StringRef Message) { Index: clang/tools/libclang/CIndexDiagnostic.h =================================================================== --- clang/tools/libclang/CIndexDiagnostic.h +++ clang/tools/libclang/CIndexDiagnostic.h @@ -89,6 +89,9 @@ virtual CXString getFixIt(unsigned FixIt, CXSourceRange *ReplacementRange) const = 0; + /// Return the documentation URLs associated with the diagnostic. + virtual CXStringSet *getDocumentationURLs() const = 0; + Kind getKind() const { return K; } CXDiagnosticSetImpl &getChildDiagnostics() { @@ -150,6 +153,9 @@ CXString getFixIt(unsigned FixIt, CXSourceRange *ReplacementRange) const override; + /// Return the documentation URLs associated with the diagnostic. + CXStringSet *getDocumentationURLs() const override; + static bool classof(const CXDiagnosticImpl *D) { return D->getKind() == StoredDiagnosticKind; } Index: clang/tools/libclang/CIndexDiagnostic.cpp =================================================================== --- clang/tools/libclang/CIndexDiagnostic.cpp +++ clang/tools/libclang/CIndexDiagnostic.cpp @@ -77,6 +77,9 @@ *ReplacementRange = clang_getNullRange(); return cxstring::createEmpty(); } + CXStringSet *getDocumentationURLs() const override { + return cxstring::createSet({}); + } }; class CXDiagnosticRenderer : public DiagnosticNoteRenderer { @@ -438,6 +441,12 @@ return D->getFixIt(FixIt, ReplacementRange); } +CXStringSet *clang_getDiagnosticDocumentationURLs(CXDiagnostic Diagnostic) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diagnostic)) + return D->getDocumentationURLs(); + return cxstring::createSet({}); +} + void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) { if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl *>(Diags)) { if (D->isExternallyManaged()) Index: clang/tools/c-index-test/c-index-test.c =================================================================== --- clang/tools/c-index-test/c-index-test.c +++ clang/tools/c-index-test/c-index-test.c @@ -1189,10 +1189,11 @@ FILE *out = stderr; CXFile file; CXString Msg; + CXStringSet *DocumentationURLs = NULL; unsigned display_opts = CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges | CXDiagnostic_DisplayOption; - unsigned i, num_fixits; + unsigned i, count; if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored) return; @@ -1206,9 +1207,9 @@ if (!file) return; - num_fixits = clang_getDiagnosticNumFixIts(Diagnostic); - fprintf(stderr, "Number FIX-ITs = %d\n", num_fixits); - for (i = 0; i != num_fixits; ++i) { + count = clang_getDiagnosticNumFixIts(Diagnostic); + fprintf(stderr, "Number FIX-ITs = %d\n", count); + for (i = 0; i != count; ++i) { CXSourceRange range; CXString insertion_text = clang_getDiagnosticFixIt(Diagnostic, i, &range); CXSourceLocation start = clang_getRangeStart(range); @@ -1240,6 +1241,14 @@ } clang_disposeString(insertion_text); } + + DocumentationURLs = clang_getDiagnosticDocumentationURLs(Diagnostic); + if (DocumentationURLs) { + for (i = 0, count = DocumentationURLs->Count; i < count; ++i) + printf("[Documentation URL: %s]\n", + clang_getCString(DocumentationURLs->Strings[i])); + clang_disposeStringSet(DocumentationURLs); + } } void PrintDiagnosticSet(CXDiagnosticSet Set) { @@ -4669,6 +4678,17 @@ } } +static void printDocumentationURLs(CXDiagnostic D, unsigned indent) { + unsigned i, count; + CXStringSet *DocumentationURLs = clang_getDiagnosticDocumentationURLs(D); + for (i = 0, count = DocumentationURLs->Count; i < count; ++i) { + printIndent(indent); + printf("[Documentation URL: %s]\n", + clang_getCString(DocumentationURLs->Strings[i])); + } + clang_disposeStringSet(DocumentationURLs); +} + static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) { unsigned i, n; @@ -4716,7 +4736,8 @@ printRanges(D, indent); printFixIts(D, indent); - + printDocumentationURLs(D, indent); + /* Print subdiagnostics. */ printDiagnosticSet(clang_getChildDiagnostics(D), indent+2); Index: clang/test/Misc/serialized-diags-documentation.c =================================================================== --- /dev/null +++ clang/test/Misc/serialized-diags-documentation.c @@ -0,0 +1,4 @@ +// RUN: c-index-test -read-diagnostics %S/Inputs/serialized-diags-documentation.dia 2>&1 | FileCheck %s + +// CHECK: hello.swift:1:1: error: non-nominal type '(Int, Int)' cannot be extended [] [] +// CHECK: [Documentation URL: {{.*}}/doc/swift/diagnostics/nominal-types.md] Index: clang/lib/Frontend/SerializedDiagnosticReader.cpp =================================================================== --- clang/lib/Frontend/SerializedDiagnosticReader.cpp +++ clang/lib/Frontend/SerializedDiagnosticReader.cpp @@ -318,6 +318,20 @@ if ((EC = visitVersionRecord(Record[0]))) return EC; continue; + case RECORD_DOCUMENTATION_URL: + // A documentation URL has an ID and URL size. + if (Record.size() != 2) + return SDError::MalformedDiagnosticRecord; + if ((EC = visitDocumentationURLRecord(/*ID*/ Record[0], /*URL*/ Blob))) + return EC; + continue; + case RECORD_DOCUMENTATION: + // A documentation record just has an ID. + if (Record.size() != 1) + return SDError::MalformedDiagnosticRecord; + if ((EC = visitDocumentationRecord(/*ID*/ Record[0]))) + return EC; + continue; } } } Index: clang/lib/Frontend/SerializedDiagnosticPrinter.cpp =================================================================== --- clang/lib/Frontend/SerializedDiagnosticPrinter.cpp +++ clang/lib/Frontend/SerializedDiagnosticPrinter.cpp @@ -93,6 +93,7 @@ AbbrevLookup FileLookup; AbbrevLookup CategoryLookup; AbbrevLookup DiagFlagLookup; + AbbrevLookup DocumentationLookup; public: SDiagsMerger(SDiagsWriter &Writer) @@ -120,6 +121,10 @@ visitSourceRangeRecord(const serialized_diags::Location &Start, const serialized_diags::Location &End) override; + std::error_code visitDocumentationURLRecord(unsigned ID, + StringRef URL) override; + std::error_code visitDocumentationRecord(unsigned ID) override; + private: std::error_code adjustSourceLocFilename(RecordData &Record, unsigned int offset); @@ -197,6 +202,9 @@ ArrayRef<FixItHint> Hints, const SourceManager &SM); + /// Emit record(s) for diagnostic documentation URLs. + void EmitDocumentation(ArrayRef<StringRef> URLs); + /// Emit a record for a CharSourceRange. void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM); @@ -212,6 +220,9 @@ /// Emit (lazily) the file string and retrieved the file identifier. unsigned getEmitFile(const char *Filename); + /// Lazily emit a diagnostic documentation URL. + unsigned getEmitDocumentationURL(StringRef URL); + /// Add SourceLocation information the specified record. void AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc, RecordDataImpl &Record, unsigned TokSize = 0); @@ -273,6 +284,9 @@ /// The collection of files used. llvm::DenseMap<const char *, unsigned> Files; + /// The collection of documentation URLs used. + llvm::DenseMap<const char *, unsigned> DocumentationURLs; + typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> > DiagFlagsTy; @@ -452,6 +466,8 @@ EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record); EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record); EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record); + EmitRecordID(RECORD_DOCUMENTATION_URL, "DocumentationURL", Stream, Record); + EmitRecordID(RECORD_DOCUMENTATION_URL, "Documentation", Stream, Record); // Emit abbreviation for RECORD_DIAG. Abbrev = std::make_shared<BitCodeAbbrev>(); @@ -508,6 +524,23 @@ Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); + // Emit the abbreviation for RECORD_DOCUMENTATION_URL. + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(RECORD_DOCUMENTATION_URL)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped doc ID. + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // URL size. + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // URL text. + Abbrevs.set(RECORD_DOCUMENTATION_URL, + Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); + + // Emit the abbreviation for RECORD_DOCUMENTATION. + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(RECORD_DOCUMENTATION)); + Abbrev->Add( + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped doc note ID. + Abbrevs.set(RECORD_DOCUMENTATION, + Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); + Stream.ExitBlock(); } @@ -566,6 +599,24 @@ return entry.first; } +unsigned SDiagsWriter::getEmitDocumentationURL(StringRef URL) { + if (URL.empty()) + return 0; + + unsigned &entry = State->DocumentationURLs[URL.data()]; + if (entry) + return entry; + + // Lazily generate the record for the URL. + entry = State->DocumentationURLs.size(); + RecordData::value_type Record[] = {RECORD_DOCUMENTATION_URL, entry, + URL.size()}; + State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_DOCUMENTATION_URL), + Record, URL); + + return entry; +} + void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { // Enter the block for a non-note diagnostic immediately, rather than waiting @@ -718,6 +769,21 @@ Writer.EmitCodeContext(Ranges, Hints, Loc.getManager()); } +void SDiagsWriter::EmitDocumentation(ArrayRef<StringRef> URLs) { + llvm::BitstreamWriter &Stream = State->Stream; + RecordData &Record = State->Record; + AbbreviationMap &Abbrevs = State->Abbrevs; + + for (ArrayRef<StringRef>::iterator I = URLs.begin(), E = URLs.end(); I != E; + ++I) { + unsigned ID = getEmitDocumentationURL(*I); + Record.clear(); + Record.push_back(ID); + Stream.EmitRecord(RECORD_DOCUMENTATION, Record, + Abbrevs.get(RECORD_DOCUMENTATION)); + } +} + void SDiagsRenderer::emitNote(FullSourceLoc Loc, StringRef Message) { Writer.EnterDiagBlock(); PresumedLoc PLoc = Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc(); @@ -858,3 +924,17 @@ DiagFlagLookup[ID] = Writer.getEmitDiagnosticFlag(Name); return std::error_code(); } + +std::error_code SDiagsMerger::visitDocumentationURLRecord(unsigned ID, + StringRef URL) { + DocumentationLookup[ID] = Writer.getEmitDocumentationURL(URL); + return std::error_code(); +} + +std::error_code SDiagsMerger::visitDocumentationRecord(unsigned ID) { + RecordData::value_type Record[] = {DocumentationLookup[ID]}; + Writer.State->Stream.EmitRecord( + RECORD_DOCUMENTATION, Record, + Writer.State->Abbrevs.get(RECORD_DOCUMENTATION)); + return std::error_code(); +} Index: clang/include/clang/Frontend/SerializedDiagnostics.h =================================================================== --- clang/include/clang/Frontend/SerializedDiagnostics.h +++ clang/include/clang/Frontend/SerializedDiagnostics.h @@ -32,8 +32,10 @@ RECORD_CATEGORY, RECORD_FILENAME, RECORD_FIXIT, + RECORD_DOCUMENTATION_URL, + RECORD_DOCUMENTATION, RECORD_FIRST = RECORD_VERSION, - RECORD_LAST = RECORD_FIXIT + RECORD_LAST = RECORD_DOCUMENTATION }; /// A stable version of DiagnosticIDs::Level. Index: clang/include/clang/Frontend/SerializedDiagnosticReader.h =================================================================== --- clang/include/clang/Frontend/SerializedDiagnosticReader.h +++ clang/include/clang/Frontend/SerializedDiagnosticReader.h @@ -121,6 +121,13 @@ return {}; } + /// Visit a diagnostic documentation URL. + virtual std::error_code visitDocumentationURLRecord(unsigned ID, + StringRef Path) { + return {}; + } + virtual std::error_code visitDocumentationRecord(unsigned ID) { return {}; } + /// Visit the version of the set of diagnostics. virtual std::error_code visitVersionRecord(unsigned Version) { return {}; } }; Index: clang/include/clang-c/Index.h =================================================================== --- clang/include/clang-c/Index.h +++ clang/include/clang-c/Index.h @@ -1103,6 +1103,20 @@ CINDEX_LINKAGE CXString clang_getDiagnosticFixIt( CXDiagnostic Diagnostic, unsigned FixIt, CXSourceRange *ReplacementRange); +/** + * Retrieve the documentation URLs associated with the given diagnostic. + * + * Linked documentation is intended to be displayed alongside emitted + * diagnostics to teach users about relevant language concepts or describe + * common problems and solutions when encountering errors. + * + * \param Diagnostic The diagnostic whose documentation URLs are being queried. + * + * \returns A set of strings which represent URLs to external documentation. + */ +CINDEX_LINKAGE CXStringSet * +clang_getDiagnosticDocumentationURLs(CXDiagnostic Diagnostic); + /** * @} */
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits