================
@@ -7,108 +7,228 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/SARIFDiagnostic.h"
-#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Basic/FileManager.h"
+#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/Sarif.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/Locale.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <string>
namespace clang {
+// In sarif mode,
+// a diagnostics 'group' have 1 top-level error/warning and several sub-level
+// notes. For example:
+//
+// error: static assertion failed.
+// note: in instantiation of 'cat::meow'.
+// note: because concept 'paper_tiger' would be invalid.
+// error: invalid operands to binary expression 'cat::meow' and 'dog::wolf'.
+// note: candidate function not viable.
+// note: no known conversion from 'tiger::meooooow' to 'cat::meow'
+// note: candidate function ignored.
+// note: constraints not satisfied.
+// note: ... (candidates)
+// note: ... (reasons)
+// note: too many candidates.
+// error: too many errors occured, stopping now.
+
SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
DiagnosticOptions &DiagOpts,
SarifDocumentWriter *Writer)
- : DiagnosticRenderer(LangOpts, DiagOpts), Writer(Writer) {}
+ : DiagnosticRenderer(LangOpts, DiagOpts),
+ Root(Node::Result(), Node::Option{&LangOpts, &DiagOpts},
+ /*Nesting=*/-1), // The root does not represents a diagnostic.
+ Current(&Root), Writer(Writer) {
+ // Don't print 'X warnings and Y errors generated'.
+ DiagOpts.ShowCarets = false;
+}
+
+// helper function
+namespace {
+template <class NodeType, class IterateFuncType, class ApplyFuncType>
+void RecursiveFor(NodeType &&Node, IterateFuncType &&IterateFunc,
+ ApplyFuncType &&ApplyFunc) {
+ for (auto &&Child : IterateFunc(Node)) {
+ ApplyFunc(*Child);
+ RecursiveFor(*Child, IterateFunc, ApplyFunc);
+ }
+}
+} // namespace
+
+SARIFDiagnostic::~SARIFDiagnostic() {
+ // clang-format off
+ for (auto& TopLevelDiagnosticsPtr : Root.getChildrenPtrs()) { // For each
top-level error/warnings.
+ unsigned DiagID = TopLevelDiagnosticsPtr->getDiagID();
+ SarifRule Rule = SarifRule::create() // Each top-level error/warning has a
corresponding Rule.
+ .setRuleId(std::to_string(DiagID))
+ .setDefaultConfiguration(
+ SarifReportingConfiguration::create()
+ .setLevel(
+ TopLevelDiagnosticsPtr->getLevel() ==
DiagnosticsEngine::Level::Note ? SarifResultLevel::Note :
+ TopLevelDiagnosticsPtr->getLevel() ==
DiagnosticsEngine::Level::Remark ? SarifResultLevel::Note :
+ TopLevelDiagnosticsPtr->getLevel() ==
DiagnosticsEngine::Level::Warning ? SarifResultLevel::Warning :
+ TopLevelDiagnosticsPtr->getLevel() ==
DiagnosticsEngine::Level::Error ? SarifResultLevel::Error :
+ TopLevelDiagnosticsPtr->getLevel() ==
DiagnosticsEngine::Level::Fatal ? SarifResultLevel::Error :
+ (assert(false && "Invalid diagnostic
type"), SarifResultLevel::None)
+ )
+ .setRank(
+ TopLevelDiagnosticsPtr->getLevel() <=
DiagnosticsEngine::Level::Warning ? 0 :
+ TopLevelDiagnosticsPtr->getLevel() ==
DiagnosticsEngine::Level::Error ? 50 :
+ TopLevelDiagnosticsPtr->getLevel() ==
DiagnosticsEngine::Level::Fatal ? 100 :
+ (assert(false && "Invalid diagnostic
type"), 0)
+ )
+ );
+ unsigned RuleIndex = Writer->createRule(Rule); // Write into Writer.
+
+ SarifResult Result = SarifResult::create(RuleIndex)
+ .setDiagnosticMessage(TopLevelDiagnosticsPtr->getDiagnosticMessage())
+ .addLocations(TopLevelDiagnosticsPtr->getLocations())
+ .addRelatedLocations(TopLevelDiagnosticsPtr->getRelatedLocations());
+ RecursiveFor(*TopLevelDiagnosticsPtr, [] (Node& Node) -> auto& { return
Node.getChildrenPtrs(); }, [&] (Node& Node) { // For each (recursive)
ChildResults.
+ Result.addRelatedLocations({
+ SarifChildResult::create()
+ .setDiagnosticMessage(Node.getDiagnosticMessage())
+ .addLocations(Node.getLocations())
+ .setNesting(Node.getNesting())
+ });
+ Result.addRelatedLocations(Node.getRelatedLocations());
+ });
+ Writer->appendResult(Result); // Write into Writer
+ }
+ // clang-format on
+}
-// FIXME(llvm-project/issues/57323): Refactor Diagnostic classes.
void SARIFDiagnostic::emitDiagnosticMessage(
FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,
StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
- DiagOrStoredDiag D) {
+ DiagOrStoredDiag Diag) {
+
+ if (Level >= DiagnosticsEngine::Level::Warning) {
+ Current =
+ &Root; // If this is a top-level error/warning, repoint Current to
Root.
+ } else {
+ if (Message.starts_with("candidate"))
+ Current =
+ &Current
+ ->getForkableParent(); // If this is an forked-case note,
repoint
+ // Current to the nearest forkable Node.
+ }
+ Current = &Current->addChildResult(
+ Node::Result{Level, std::string(Message),
+ Diag}); // add child to the parent error/warning/note Node.
+ Current = &Current->addLocation(
+ Node::Location{Loc, PLoc, llvm::SmallVector<CharSourceRange>(Ranges)});
+}
- const auto *Diag = D.dyn_cast<const Diagnostic *>();
+void SARIFDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc)
{
+ Current = &Current->addRelatedLocation(Node::Location{Loc, PLoc, {}});
+}
- if (!Diag)
- return;
+void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) {
+ Current = &Current->addRelatedLocation(Node::Location{Loc, PLoc, {}});
+}
- SarifRule Rule =
SarifRule::create().setRuleId(std::to_string(Diag->getID()));
+SARIFDiagnostic::Node::Node(Result Result_, Option Option_, int Nesting)
+ : Result_(std::move(Result_)), Option_(std::move(Option_)),
+ Nesting(Nesting) {}
- Rule = addDiagnosticLevelToRule(Rule, Level);
+SARIFDiagnostic::Node &SARIFDiagnostic::Node::getParent() {
+ assert(ParentPtr && "getParent() of SARIFDiagnostic::Root!");
+ return *ParentPtr;
+}
- unsigned RuleIdx = Writer->createRule(Rule);
+SARIFDiagnostic::Node &SARIFDiagnostic::Node::getForkableParent() {
+ Node *Ptr = this;
+ while (Ptr->getLevel() <=
+ DiagnosticsEngine::Note) // The forkable node here "is and only is"
+ // warning/error/fatal.
+ Ptr = &Ptr->getParent();
+ return *Ptr;
+}
- SarifResult Result =
- SarifResult::create(RuleIdx).setDiagnosticMessage(Message);
+llvm::SmallVector<std::unique_ptr<SARIFDiagnostic::Node>> &
+SARIFDiagnostic::Node::getChildrenPtrs() {
+ return ChildrenPtrs;
+}
- if (Loc.isValid())
- Result = addLocationToResult(Result, Loc, PLoc, Ranges, *Diag);
+SARIFDiagnostic::Node &
+SARIFDiagnostic::Node::addChildResult(Result ChildResult) {
+ ChildrenPtrs.push_back(
+ std::make_unique<Node>(Node::Result(std::move(ChildResult)),
+ Node::Option(std::move(Option_)), Nesting + 1));
+ ChildrenPtrs.back()->ParentPtr = this; // I am the parent of this new child.
+ return *ChildrenPtrs.back();
+}
- for (auto &[RelLoc, RelPLoc] : RelatedLocationsCache)
- Result = addRelatedLocationToResult(Result, RelLoc, RelPLoc);
- RelatedLocationsCache.clear();
+SARIFDiagnostic::Node &SARIFDiagnostic::Node::addLocation(Location Location) {
+ Locations.push_back(std::move(Location));
+ return *this;
+}
- Writer->appendResult(Result);
+SARIFDiagnostic::Node &
+SARIFDiagnostic::Node::addRelatedLocation(Location Location) {
+ RelatedLocations.push_back(std::move(Location));
+ return *this;
}
-void SARIFDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc)
{
- // We always emit include location before results, for example:
- //
- // In file included from ...
- // In file included from ...
- // error: ...
- //
- // At this time We cannot peek the SarifRule. But what we
- // do is to push it into a cache and wait for next time
- // \ref SARIFDiagnostic::emitDiagnosticMessage to pick it up.
- RelatedLocationsCache.push_back({Loc, PLoc});
+unsigned SARIFDiagnostic::Node::getDiagID() {
+ return llvm::isa<const Diagnostic *>(Result_.Diag)
+ ? Result_.Diag.dyn_cast<const Diagnostic *>()->getID()
+ : Result_.Diag.dyn_cast<const StoredDiagnostic *>()->getID();
}
-void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
- StringRef ModuleName) {
- RelatedLocationsCache.push_back({Loc, PLoc});
+DiagnosticsEngine::Level SARIFDiagnostic::Node::getLevel() {
+ return Result_.Level;
+}
+
+std::string SARIFDiagnostic::Node::getDiagnosticMessage() {
+ return Result_.Message;
}
-SarifResult SARIFDiagnostic::addLocationToResult(
- SarifResult Result, FullSourceLoc Loc, PresumedLoc PLoc,
- ArrayRef<CharSourceRange> Ranges, const Diagnostic &Diag) {
- auto Locations = getSarifLocation(Loc, PLoc, Ranges);
- return Result.addLocations(Locations);
+llvm::SmallVector<CharSourceRange> SARIFDiagnostic::Node::getLocations() {
+ llvm::SmallVector<CharSourceRange> CharSourceRanges;
+ std::for_each(Locations.begin(), Locations.end(), [&](Location &Location) {
+ CharSourceRanges.append(Location.getCharSourceRangesWithOption(Option_));
+ });
+ return CharSourceRanges;
}
-SarifResult SARIFDiagnostic::addRelatedLocationToResult(SarifResult Result,
- FullSourceLoc Loc,
- PresumedLoc PLoc) {
- auto Locations = getSarifLocation(Loc, PLoc, {});
- return Result.addRelatedLocations(Locations);
+llvm::SmallVector<CharSourceRange>
+SARIFDiagnostic::Node::getRelatedLocations() {
+ llvm::SmallVector<CharSourceRange> CharSourceRanges;
+ std::for_each(RelatedLocations.begin(), RelatedLocations.end(),
+ [&](Location &RelatedLocation) {
+ CharSourceRanges.append(
+ RelatedLocation.getCharSourceRangesWithOption(Option_));
+ });
+ return CharSourceRanges;
}
+int SARIFDiagnostic::Node::getNesting() { return Nesting; }
+
llvm::SmallVector<CharSourceRange>
-SARIFDiagnostic::getSarifLocation(FullSourceLoc Loc, PresumedLoc PLoc,
- ArrayRef<CharSourceRange> Ranges) {
+SARIFDiagnostic::Node::Location::getCharSourceRangesWithOption(Option Option) {
SmallVector<CharSourceRange> Locations = {};
if (PLoc.isInvalid()) {
+ // FIXME(llvm-project/issues/57366): File-only locations
// At least add the file name if available:
FileID FID = Loc.getFileID();
if (FID.isValid()) {
if (OptionalFileEntryRef FE = Loc.getFileEntryRef()) {
- emitFilename(FE->getName(), Loc.getManager());
- // FIXME(llvm-project/issues/57366): File-only locations
+ // EmitFilename(FE->getName(), Loc.getManager());
----------------
Sirraide wrote:
I feel like `emitFilename` is a bad name then but that’s not really an issue w/
this patch; also on that note, I’m pretty sure the code to get and normalise
the filename is copy-pasted from the text diagnostic renderer, so we should
probably factor that out into a separate function
https://github.com/llvm/llvm-project/pull/174106
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits