Index: llvm/include/llvm/Support/FileCheck.h =================================================================== --- llvm/include/llvm/Support/FileCheck.h +++ llvm/include/llvm/Support/FileCheck.h @@ -87,7 +87,7 @@ /// What is the FileCheck directive for this diagnostic? Check::FileCheckType CheckTy; /// Where is the FileCheck directive for this diagnostic? - unsigned CheckLine, CheckCol; + SMLoc CheckLoc; /// What type of match result does this diagnostic describe? /// /// A directive's supplied pattern is said to be either expected or excluded Index: llvm/lib/Support/FileCheck.cpp =================================================================== --- llvm/lib/Support/FileCheck.cpp +++ llvm/lib/Support/FileCheck.cpp @@ -1038,16 +1038,13 @@ const Check::FileCheckType &CheckTy, SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange) - : CheckTy(CheckTy), MatchTy(MatchTy) { + : CheckTy(CheckTy), CheckLoc(CheckLoc), MatchTy(MatchTy) { auto Start = SM.getLineAndColumn(InputRange.Start); auto End = SM.getLineAndColumn(InputRange.End); InputStartLine = Start.first; InputStartCol = Start.second; InputEndLine = End.first; InputEndCol = End.second; - Start = SM.getLineAndColumn(CheckLoc); - CheckLine = Start.first; - CheckCol = Start.second; } static bool IsPartOfWord(char c) { Index: llvm/test/FileCheck/dump-input-annotations.txt =================================================================== --- llvm/test/FileCheck/dump-input-annotations.txt +++ llvm/test/FileCheck/dump-input-annotations.txt @@ -494,3 +494,64 @@ ; LAB-NEXT: label:3'0 ~~~ ; LAB-NEXT: >>>>>> ; LAB-NOT: {{.}} + +;-------------------------------------------------- +; --implicit-check-not +; +; The first two --implicit-check-not patterns have no match (success). The +; third has an unexpected match (error). To check per-input-line annotation +; sorting, all of those plus the CHECK directives have annotations on the same +; input line. +;-------------------------------------------------- + +; RUN: echo 'hello world again!' > %t.in + +; RUN: echo 'CHECK: hel' > %t.chk +; RUN: echo 'CHECK: wor' >> %t.chk +; RUN: echo 'CHECK: !' >> %t.chk + +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck -dump-input=always -input-file=%t.in %t.chk 2>&1 \ +; RUN: --implicit-check-not='goodbye' \ +; RUN: --implicit-check-not='world' \ +; RUN: --implicit-check-not='again' \ +; RUN: | FileCheck -match-full-lines %s -check-prefix=IMPNOT \ +; RUN: -implicit-check-not='remark:' +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck -dump-input=always -input-file=%t.in %t.chk -v 2>&1 \ +; RUN: --implicit-check-not='goodbye' \ +; RUN: --implicit-check-not='world' \ +; RUN: --implicit-check-not='again' \ +; RUN: | FileCheck -match-full-lines %s -check-prefixes=IMPNOT,IMPNOT-V \ +; RUN: -implicit-check-not='remark:' +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck -dump-input=always -input-file=%t.in %t.chk -vv 2>&1 \ +; RUN: --implicit-check-not='goodbye' \ +; RUN: --implicit-check-not='world' \ +; RUN: --implicit-check-not='again' \ +; RUN: | FileCheck -match-full-lines %s \ +; RUN: -check-prefixes=IMPNOT,IMPNOT-V,IMPNOT-VV \ +; RUN: -implicit-check-not='remark:' + +; Verbose diagnostics are suppressed but not errors. +; IMPNOT:{{.*}}error:{{.*}} + +; FIXME: All occurrences of imp1, imp2, and imp3 are sorting after the first +; directive. They should instead be sorted by when they execute. + +; IMPNOT:<<<<<< +; IMPNOT-NEXT: 1: hello world again! +; IMPNOT-V-NEXT:check:1 ^~~ +; IMPNOT-VV-NEXT:not:imp1 X +; IMPNOT-VV-NEXT:not:imp2 X +; IMPNOT-VV-NEXT:not:imp3 X +; IMPNOT-VV-NEXT:not:imp1 X~~ +; IMPNOT-VV-NEXT:not:imp2 X~~ +; IMPNOT-VV-NEXT:not:imp3 X~~ +; IMPNOT-VV-NEXT:not:imp1 X~~~~~~~ +; IMPNOT-VV-NEXT:not:imp2 X~~~~~~~ +; IMPNOT-NEXT:not:imp3 !~~~~ error: no match expected +; IMPNOT-V-NEXT:check:2 ^~~ +; IMPNOT-V-NEXT:check:3 ^ +; IMPNOT-NEXT:>>>>>> +; IMPNOT-NOT:{{.}} Index: llvm/utils/FileCheck/FileCheck.cpp =================================================================== --- llvm/utils/FileCheck/FileCheck.cpp +++ llvm/utils/FileCheck/FileCheck.cpp @@ -193,14 +193,15 @@ // Labels for annotation lines. OS << " - "; WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L"; - OS << " labels the only match result for a pattern of type T from " - << "line L of\n" - << " the check file\n"; + OS << " labels the only match result for either (1) a pattern of type T" + << " from\n" + << " line L of the check file if L is an integer or (2) the" + << " I-th implicit\n" + << " pattern if L is \"imp\" followed by an integer " + << "I (index origin one)\n"; OS << " - "; WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N"; - OS << " labels the Nth match result for a pattern of type T from line " - << "L of\n" - << " the check file\n"; + OS << " labels the Nth match result for such a pattern\n"; // Markers on annotation lines. OS << " - "; @@ -293,7 +294,9 @@ llvm_unreachable("unknown FileCheckType"); } -static void BuildInputAnnotations(const std::vector &Diags, +static void BuildInputAnnotations(const SourceMgr &SM, + unsigned CheckFileBufferID, + const std::vector &Diags, std::vector &Annotations, unsigned &LabelWidth) { // How many diagnostics has the current check seen so far? @@ -305,14 +308,22 @@ InputAnnotation A; // Build label, which uniquely identifies this check result. - A.CheckLine = DiagItr->CheckLine; + 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) << ":" - << DiagItr->CheckLine; + Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"; + if (CheckBufferID == CheckFileBufferID) + Label << CheckLineAndCol.first; + else + // The implicit buffer ID is the buffer ID minus the input file buffer + // and the check file buffer plus one for one-origin indexing. + Label << "imp" << (CheckBufferID - 1); A.CheckDiagIndex = UINT_MAX; auto DiagNext = std::next(DiagItr); if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy && - DiagItr->CheckLine == DiagNext->CheckLine) + DiagItr->CheckLoc == DiagNext->CheckLoc) A.CheckDiagIndex = CheckDiagCount++; else if (CheckDiagCount) { A.CheckDiagIndex = CheckDiagCount; @@ -606,9 +617,10 @@ SmallString<4096> CheckFileBuffer; StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer); - SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer( - CheckFileText, CheckFile.getBufferIdentifier()), - SMLoc()); + unsigned CheckFileBufferID = SM.AddNewSourceBuffer( + MemoryBuffer::getMemBuffer(CheckFileText, + CheckFile.getBufferIdentifier()), + SMLoc()); if (FC.readCheckFile(SM, CheckFileText, PrefixRE)) return 2; @@ -658,7 +670,8 @@ << "\n"; std::vector Annotations; unsigned LabelWidth; - BuildInputAnnotations(Diags, Annotations, LabelWidth); + BuildInputAnnotations(SM, CheckFileBufferID, Diags, Annotations, + LabelWidth); DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth); }