Skip to content

Commit e3d4870

Browse files
committed
[Frontend] Add support for named target buffer in -verify expected lines
Clang, which heavily inspired Swift's -verify flag, supports naming other files like so: ``` // [email protected]:11:22{{some error}} ``` Swift hasn't had the same need for this, because of the lack of textual header inclusion (where the same header file can emit different diagnostics depending on where it's included). The lack of this functionality has made it impossible to use -verify in cases where diagnostics are emitted in a macro however, since the expected-lines can't be placed inside the generated macro buffer. Now the main Swift file can refer to diagnostics inside these generated buffers by naming the buffers. The generated names aren't pretty, but the identifier is stable, unique and it works. Here is an example of what it can look like: ``` // expected-error@@__swiftmacro_4main3bar.swift:10:15{{no exact matches in call to initializer}} // expected-note@+1{{in expansion of macro 'foo' on global function 'bar' here}} @foo func bar() {} ``` The double "@" is a result of the buffer name starting with an @, which is unfortunate but is how the mangling scheme works for macro buffer names.
1 parent e8a9286 commit e3d4870

File tree

1 file changed

+29
-5
lines changed

1 file changed

+29
-5
lines changed

lib/Frontend/DiagnosticVerifier.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ struct ExpectedDiagnosticInfo {
202202
std::string MessageStr;
203203
unsigned LineNo = ~0U;
204204
std::optional<unsigned> ColumnNo;
205+
std::optional<unsigned> TargetBufferID;
205206

206207
using AlternativeExpectedFixIts = std::vector<ExpectedFixIt>;
207208
std::vector<AlternativeExpectedFixIts> Fixits = {};
@@ -593,6 +594,18 @@ static void validatePrefixList(ArrayRef<std::string> prefixes) {
593594
}
594595
}
595596

597+
bool parseTargetBufferName(StringRef &MatchStart, StringRef &Out, size_t &TextStartIdx) {
598+
StringRef Offs = MatchStart.slice(0, TextStartIdx);
599+
600+
size_t LineIndex = Offs.find(':');
601+
if (LineIndex == 0 || LineIndex == StringRef::npos)
602+
return false;
603+
Out = Offs.slice(1, LineIndex);
604+
MatchStart = MatchStart.substr(LineIndex);
605+
TextStartIdx -= LineIndex;
606+
return true;
607+
}
608+
596609
/// After the file has been processed, check to see if we got all of
597610
/// the expected diagnostics and check to see if there were any unexpected
598611
/// ones.
@@ -665,9 +678,17 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
665678
if (TextStartIdx > 0 && MatchStart[0] == '@') {
666679
if (MatchStart[1] != '+' && MatchStart[1] != '-' &&
667680
MatchStart[1] != ':') {
668-
addError(MatchStart.data(),
669-
"expected '+'/'-' for line offset, or ':' for column");
670-
continue;
681+
StringRef TargetBufferName;
682+
if (!parseTargetBufferName(MatchStart, TargetBufferName, TextStartIdx)) {
683+
addError(MatchStart.data(), "expected '+'/'-' for line offset, ':' "
684+
"for column, or a buffer name");
685+
continue;
686+
}
687+
Expected.TargetBufferID = SM.getIDForBufferIdentifier(TargetBufferName);
688+
if (!Expected.TargetBufferID) {
689+
addError(MatchStart.data(), "no buffer with name '" + TargetBufferName + "' found");
690+
continue;
691+
}
671692
}
672693
StringRef Offs;
673694
if (MatchStart[1] == '+')
@@ -740,7 +761,9 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
740761
Expected.MessageRange = MatchStart.slice(2, End);
741762
Expected.MessageStr =
742763
Lexer::getEncodedStringSegment(Expected.MessageRange, Buf).str();
743-
if (PrevExpectedContinuationLine)
764+
if (Expected.TargetBufferID)
765+
Expected.LineNo = 0;
766+
else if (PrevExpectedContinuationLine)
744767
Expected.LineNo = PrevExpectedContinuationLine;
745768
else
746769
Expected.LineNo = SM.getLineAndColumnInBuffer(
@@ -913,9 +936,10 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) {
913936
--i;
914937
auto &expected = ExpectedDiagnostics[i];
915938

939+
unsigned ID = expected.TargetBufferID.value_or(BufferID);
916940
// Check to see if we had this expected diagnostic.
917941
auto FoundDiagnosticInfo =
918-
findDiagnostic(CapturedDiagnostics, expected, BufferID);
942+
findDiagnostic(CapturedDiagnostics, expected, ID);
919943
auto FoundDiagnosticIter = std::get<0>(FoundDiagnosticInfo);
920944
if (FoundDiagnosticIter == CapturedDiagnostics.end()) {
921945
// Diagnostic didn't exist. If this is a 'mayAppear' diagnostic, then

0 commit comments

Comments
 (0)