diff options
Diffstat (limited to 'llvm/utils/FileCheck/FileCheck.cpp')
-rw-r--r-- | llvm/utils/FileCheck/FileCheck.cpp | 96 |
1 files changed, 55 insertions, 41 deletions
diff --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp index 6cfd0fd..ef6c62b 100644 --- a/llvm/utils/FileCheck/FileCheck.cpp +++ b/llvm/utils/FileCheck/FileCheck.cpp @@ -241,11 +241,8 @@ static void DumpInputAnnotationHelp(raw_ostream &OS) { /// An annotation for a single input line. struct InputAnnotation { - /// The check file line (one-origin indexing) where the directive that - /// produced this annotation is located. - unsigned CheckLine; - /// The index of the match result for this check. - unsigned CheckDiagIndex; + /// The index of the match result across all checks + unsigned DiagIndex; /// The label for this annotation. std::string Label; /// What input line (one-origin indexing) this annotation marks. This might @@ -253,7 +250,7 @@ struct InputAnnotation { /// a non-initial fragment of a diagnostic that has been broken across /// multiple lines. unsigned InputLine; - /// The column range (one-origin indexing, open end) in which to to mark the + /// The column range (one-origin indexing, open end) in which to mark the /// input line. If InputEndCol is UINT_MAX, treat it as the last column /// before the newline. unsigned InputStartCol, InputEndCol; @@ -300,6 +297,8 @@ BuildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID, const std::vector<FileCheckDiag> &Diags, std::vector<InputAnnotation> &Annotations, unsigned &LabelWidth) { + // How many diagnostics have we seen so far? + unsigned DiagCount = 0; // How many diagnostics has the current check seen so far? unsigned CheckDiagCount = 0; // What's the widest label? @@ -307,12 +306,12 @@ BuildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID, for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd; ++DiagItr) { InputAnnotation A; + A.DiagIndex = DiagCount++; // Build label, which uniquely identifies this check result. unsigned CheckBufferID = SM.FindBufferContainingLoc(DiagItr->CheckLoc); auto CheckLineAndCol = SM.getLineAndColumn(DiagItr->CheckLoc, CheckBufferID); - A.CheckLine = CheckLineAndCol.first; llvm::raw_string_ostream Label(A.Label); Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"; if (CheckBufferID == CheckFileBufferID) @@ -323,19 +322,17 @@ BuildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID, else llvm_unreachable("expected diagnostic's check location to be either in " "the check file or for an implicit pattern"); - A.CheckDiagIndex = UINT_MAX; + unsigned CheckDiagIndex = UINT_MAX; auto DiagNext = std::next(DiagItr); if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy && DiagItr->CheckLoc == DiagNext->CheckLoc) - A.CheckDiagIndex = CheckDiagCount++; + CheckDiagIndex = CheckDiagCount++; else if (CheckDiagCount) { - A.CheckDiagIndex = CheckDiagCount; + CheckDiagIndex = CheckDiagCount; CheckDiagCount = 0; } - if (A.CheckDiagIndex != UINT_MAX) - Label << "'" << A.CheckDiagIndex; - else - A.CheckDiagIndex = 0; + if (CheckDiagIndex != UINT_MAX) + Label << "'" << CheckDiagIndex; Label.flush(); LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size()); @@ -366,8 +363,7 @@ BuildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID, if (DiagItr->InputEndCol == 1 && L == E) break; InputAnnotation B; - B.CheckLine = A.CheckLine; - B.CheckDiagIndex = A.CheckDiagIndex; + B.DiagIndex = A.DiagIndex; B.Label = A.Label; B.InputLine = L; B.Marker = A.Marker; @@ -392,35 +388,53 @@ static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req, OS << "Full input was:\n<<<<<<\n"; // Sort annotations. - // - // First, sort in the order of input lines to make it easier to find relevant - // annotations while iterating input lines in the implementation below. - // FileCheck diagnostics are not always reported and recorded in the order of - // input lines due to, for example, CHECK-DAG and CHECK-NOT. - // - // Second, for annotations for the same input line, sort in the order of the - // FileCheck directive's line in the check file (where there's at most one - // directive per line) and then by the index of the match result for that - // directive. The rationale of this choice is that, for any input line, this - // sort establishes a total order of annotations that, with respect to match - // results, is consistent across multiple lines, thus making match results - // easier to track from one line to the next when they span multiple lines. std::sort(Annotations.begin(), Annotations.end(), [](const InputAnnotation &A, const InputAnnotation &B) { + // 1. Sort annotations in the order of the input lines. + // + // This makes it easier to find relevant annotations while + // iterating input lines in the implementation below. FileCheck + // does not always produce diagnostics in the order of input + // lines due to, for example, CHECK-DAG and CHECK-NOT. if (A.InputLine != B.InputLine) return A.InputLine < B.InputLine; - if (A.CheckLine != B.CheckLine) - return A.CheckLine < B.CheckLine; - // FIXME: Sometimes CHECK-LABEL reports its match twice with - // other diagnostics in between, and then diag index incrementing - // fails to work properly, and then this assert fails. We should - // suppress one of those diagnostics or do a better job of - // computing this index. For now, we just produce a redundant - // CHECK-LABEL annotation. - // assert(A.CheckDiagIndex != B.CheckDiagIndex && - // "expected diagnostic indices to be unique within a " - // " check line"); - return A.CheckDiagIndex < B.CheckDiagIndex; + // 2. Sort annotations in the temporal order FileCheck produced + // their associated diagnostics. + // + // This sort offers several benefits: + // + // A. On a single input line, the order of annotations reflects + // the FileCheck logic for processing directives/patterns. + // This can be helpful in understanding cases in which the + // order of the associated directives/patterns in the check + // file or on the command line either (i) does not match the + // temporal order in which FileCheck looks for matches for the + // directives/patterns (due to, for example, CHECK-LABEL, + // CHECK-NOT, or `--implicit-check-not`) or (ii) does match + // that order but does not match the order of those + // diagnostics along an input line (due to, for example, + // CHECK-DAG). + // + // On the other hand, because our presentation format presents + // input lines in order, there's no clear way to offer the + // same benefit across input lines. For consistency, it might + // then seem worthwhile to have annotations on a single line + // also sorted in input order (that is, by input column). + // However, in practice, this appears to be more confusing + // than helpful. Perhaps it's intuitive to expect annotations + // to be listed in the temporal order in which they were + // produced except in cases the presentation format obviously + // and inherently cannot support it (that is, across input + // lines). + // + // B. When diagnostics' annotations are split among multiple + // input lines, the user must track them from one input line + // to the next. One property of the sort chosen here is that + // it facilitates the user in this regard by ensuring the + // following: when comparing any two input lines, a + // diagnostic's annotations are sorted in the same position + // relative to all other diagnostics' annotations. + return A.DiagIndex < B.DiagIndex; }); // Compute the width of the label column. |