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

Reply via email to