Skip to content

[Serialized diagnostics] Encode category documentation URL in existing record #10326

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions clang/include/clang-c/CXDiagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,14 @@ clang_getDiagnosticCategoryName(unsigned Category);
*/
CINDEX_LINKAGE CXString clang_getDiagnosticCategoryText(CXDiagnostic);

/**
* Retrieve the diagnostic category's URL for a given diagnostic.
*
* \returns The URL that provides additional documentation for the
* category of this diagnostic.
*/
CINDEX_LINKAGE CXString clang_getDiagnosticCategoryURL(CXDiagnostic);

/**
* Determine the number of source ranges associated with the given
* diagnostic.
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/Frontend/SerializedDiagnosticReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,21 @@ class SerializedDiagnosticReader {
virtual std::error_code visitEndOfDiagnostic() { return {}; }

/// Visit a category. This associates the category \c ID to a \c Name.
///
/// This entrypoint has been superseded by the overload that follows, which
/// also takes a (possibly-empty) URL providing additional documentation for
/// the category.
virtual std::error_code visitCategoryRecord(unsigned ID, StringRef Name) {
return {};
}

/// Visit a category. This associates the category \c ID to a \c Name with
/// a (possibly empty) URL.
virtual std::error_code visitCategoryRecord(unsigned ID, StringRef Name,
StringRef URL) {
return visitCategoryRecord(ID, Name);
}

/// Visit a flag. This associates the flag's \c ID to a \c Name.
virtual std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) {
return {};
Expand Down
19 changes: 17 additions & 2 deletions clang/lib/Frontend/SerializedDiagnosticReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,13 +266,28 @@ SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
continue;

switch ((RecordIDs)RecID) {
case RECORD_CATEGORY:
case RECORD_CATEGORY: {
// A category has ID and name size.
if (Record.size() != 2)
return SDError::MalformedDiagnosticRecord;
if ((EC = visitCategoryRecord(Record[0], Blob)))

// Make sure the name size makes sense.
unsigned NameLen = Record[1];
if (NameLen > Blob.size())
return SDError::MalformedDiagnosticRecord;

StringRef Name = Blob.substr(0, NameLen);
StringRef URL;

// If the name didn't take up the full blob, and the character that
// follows it is an '@', the rest is the category URL.
if (NameLen < Blob.size() && Blob[NameLen] == '@')
URL = Blob.substr(NameLen + 1);

if ((EC = visitCategoryRecord(Record[0], Name, URL)))
return EC;
continue;
}
case RECORD_DIAG:
// A diagnostic has severity, location (4), category, flag, and message
// size.
Expand Down
12 changes: 10 additions & 2 deletions clang/tools/c-index-test/c-index-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -4803,9 +4803,10 @@ static void printDiagnosticSet(
CXSourceLocation DiagLoc;
CXDiagnostic D;
CXFile File;
CXString FileName, DiagSpelling, DiagOption, DiagCat;
CXString FileName, DiagSpelling, DiagOption, DiagCat, DiagCatURL;
unsigned line, column, offset;
const char *FileNameStr = 0, *DiagOptionStr = 0, *DiagCatStr = 0;
const char *FileNameStr = 0, *DiagOptionStr = 0, *DiagCatStr = 0,
*DiagCatURLStr = 0;
const char *FileContents = 0;

D = clang_getDiagnosticInSet(Diags, i);
Expand Down Expand Up @@ -4863,13 +4864,20 @@ static void printDiagnosticSet(
fprintf(stderr, "%s\nEND CONTENTS OF FILE\n", FileContents);
}

DiagCatURL = clang_getDiagnosticCategoryURL(D);
DiagCatURLStr = clang_getCString(DiagCatURL);
if (DiagCatURLStr && DiagCatStr && DiagCatURLStr[0]) {
fprintf(stderr, "[%s]: <%s>\n", DiagCatStr, DiagCatURLStr);
}

/* Print subdiagnostics. */
printDiagnosticSet(clang_getChildDiagnostics(D), indent+2, TopDiags);

clang_disposeString(FileName);
clang_disposeString(DiagSpelling);
clang_disposeString(DiagOption);
clang_disposeString(DiagCat);
clang_disposeString(DiagCatURL);
}
}

Expand Down
9 changes: 8 additions & 1 deletion clang/tools/libclang/CIndexDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class CXDiagnosticCustomNoteImpl : public CXDiagnosticImpl {

unsigned getCategory() const override { return 0; }
CXString getCategoryText() const override { return cxstring::createEmpty(); }
CXString getCategoryURL() const override { return cxstring::createEmpty(); }

unsigned getNumRanges() const override { return 0; }
CXSourceRange getRange(unsigned Range) const override {
Expand Down Expand Up @@ -430,7 +431,13 @@ CXString clang_getDiagnosticCategoryText(CXDiagnostic Diag) {
return D->getCategoryText();
return cxstring::createEmpty();
}


CXString clang_getDiagnosticCategoryURL(CXDiagnostic Diag) {
if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
return D->getCategoryURL();
return cxstring::createEmpty();
}

unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
return D->getNumRanges();
Expand Down
6 changes: 6 additions & 0 deletions clang/tools/libclang/CIndexDiagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ class CXDiagnosticImpl {
/// Return the category string of the diagnostic.
virtual CXString getCategoryText() const = 0;

/// Return the category URL of the diagnostic.
virtual CXString getCategoryURL() const = 0;

/// Return the number of source ranges for the diagnostic.
virtual unsigned getNumRanges() const = 0;

Expand Down Expand Up @@ -160,6 +163,9 @@ struct CXStoredDiagnostic : public CXDiagnosticImpl {
/// Return the category string of the diagnostic.
CXString getCategoryText() const override;

/// Return the category URL of the diagnostic.
CXString getCategoryURL() const override;

/// Return the number of source ranges for the diagnostic.
unsigned getNumRanges() const override;

Expand Down
13 changes: 11 additions & 2 deletions clang/tools/libclang/CXLoadedDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class CXLoadedDiagnosticSetImpl : public CXDiagnosticSetImpl {

llvm::BumpPtrAllocator Alloc;
Strings Categories;
Strings CategoryURLs;
Strings WarningFlags;
Strings FileNames;

Expand Down Expand Up @@ -126,6 +127,10 @@ CXString CXLoadedDiagnostic::getCategoryText() const {
return cxstring::createDup(CategoryText);
}

CXString CXLoadedDiagnostic::getCategoryURL() const {
return cxstring::createDup(CategoryURL);
}

unsigned CXLoadedDiagnostic::getNumRanges() const {
return Ranges.size();
}
Expand Down Expand Up @@ -215,7 +220,8 @@ class DiagLoader : serialized_diags::SerializedDiagnosticReader {
std::error_code visitStartOfDiagnostic() override;
std::error_code visitEndOfDiagnostic() override;

std::error_code visitCategoryRecord(unsigned ID, StringRef Name) override;
std::error_code visitCategoryRecord(unsigned ID, StringRef Name,
StringRef URL) override;

std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) override;

Expand Down Expand Up @@ -345,11 +351,13 @@ std::error_code DiagLoader::visitEndOfDiagnostic() {
return std::error_code();
}

std::error_code DiagLoader::visitCategoryRecord(unsigned ID, StringRef Name) {
std::error_code DiagLoader::visitCategoryRecord(unsigned ID, StringRef Name,
StringRef URL) {
// FIXME: Why do we care about long strings?
if (Name.size() > 65536)
return reportInvalidFile("Out-of-bounds string in category");
TopDiags->Categories[ID] = TopDiags->copyString(Name);
TopDiags->CategoryURLs[ID] = TopDiags->copyString(URL);
return std::error_code();
}

Expand Down Expand Up @@ -431,6 +439,7 @@ std::error_code DiagLoader::visitDiagnosticRecord(
D.category = Category;
D.DiagOption = Flag ? TopDiags->WarningFlags[Flag] : "";
D.CategoryText = Category ? TopDiags->Categories[Category] : "";
D.CategoryURL = Category ? TopDiags->CategoryURLs[Category] : "";
D.Spelling = TopDiags->copyString(Message);
return std::error_code();
}
Expand Down
4 changes: 4 additions & 0 deletions clang/tools/libclang/CXLoadedDiagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ class CXLoadedDiagnostic : public CXDiagnosticImpl {
/// Return the category string of the diagnostic.
CXString getCategoryText() const override;

/// Return the category URL of the diagnostic.
CXString getCategoryURL() const override;

/// Return the number of source ranges for the diagnostic.
unsigned getNumRanges() const override;

Expand Down Expand Up @@ -89,6 +92,7 @@ class CXLoadedDiagnostic : public CXDiagnosticImpl {
const char *Spelling;
llvm::StringRef DiagOption;
llvm::StringRef CategoryText;
llvm::StringRef CategoryURL;
unsigned severity;
unsigned category;
};
Expand Down
5 changes: 5 additions & 0 deletions clang/tools/libclang/CXStoredDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ CXString CXStoredDiagnostic::getCategoryText() const {
return cxstring::createRef(DiagnosticIDs::getCategoryNameFromID(catID));
}

CXString CXStoredDiagnostic::getCategoryURL() const {
// Clang does not currently provide URLs for its own diagnostics.
return cxstring::createEmpty();
}

unsigned CXStoredDiagnostic::getNumRanges() const {
if (Diag.getLocation().isInvalid())
return 0;
Expand Down
1 change: 1 addition & 0 deletions clang/tools/libclang/libclang.map
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ LLVM_13 {
clang_getDiagnosticCategory;
clang_getDiagnosticCategoryName;
clang_getDiagnosticCategoryText;
clang_getDiagnosticCategoryURL;
clang_getDiagnosticFixIt;
clang_getDiagnosticInSet;
clang_getDiagnosticLocation;
Expand Down