TextDiagnostic: Tab handling and newlines in FixIt lines

Hi,

I am just struggling around with tabs and new lines in TextDiagnostic.cpp. Right now, I am writing a clang-tidy check to transform

int a, b, c;
int k1 = 0, k2 = 0;

into

int a;
int b;
int c;

int k1 = 0;
int k2 = 0;

and came across some issues.

  1. buildFixItInsertionLine ignores lines with \n or \r. Is there any specific reason not to show these lines (despite that everything is called Line and not Lines and probably not checked for Lines)?
  2. I am getting odd results for lines containing multiple tabs:

Diag << FixItHint::CreateInsertion(…, “Hallo\tTab\tTab\tX”); // gets fired twice (for a,b,c and k1,k2 line)

==>

Hallo…Tab…Tab…X
Hallo…Tab…Tab…X

Seems to be that

static int bytesSincePreviousTabOrLineBegin(StringRef SourceLine, size_t i) {
int bytes = 0;
while (0<i) {
if (SourceLine[–i]==’\t’)
break;
++bytes;
}
return bytes;
}

is guilty. As far as I can see, the prefix-decrement should be a postfix, thus SourceLine[i–]. Now the result is as expected:

Hallo…Tab…Tab…X
Hallo…Tab…Tab…X

Now, splitting up the declaration statement and keeping indentation, as Rewriter::InsertText(…indentNewLines=true) does, works well.

  1. Are there any tests for TextDiagnostic.cpp? I could find one.

Running check-clang-misc gives me an error for tabstop.c. The postfix doesn’t seem right and messes around with the tabstop. So,

“Hallo…Tab…Tab…X” was right and
“Hallo…Tab…Tab…X” wrong, since tabstop is default 8.

<>

Hallo…Tab…Tab…X
Hallo…Tab…Tab…X

<>

Is also correct, since the messages are fired at different indentation levels. So, after I made a complete turn, how do I display a multi-line diagnostic and FixItHint.

I have:

DeclStmt declstmt: int a, b, c;
std::string allSingleDecls = “int a;\nint b;\nint c;”; // <<— necessary whitespaces to keep indentation might be inserted

auto Diag = diag(declStmt->getSourceRange().getBegin(), “declaration statement can be split up into single line declarations”);
Diag << FixItHint::CreateReplacement(declStmt->getSourceRange(), allSingleDecls);

The FixIt is applied correct to the source file with -fix, but I would like to see a nice diagnostic-output as well.

Thanks.

Seems to work now. The only change I have made so far is in TextDiagnostic.cpp:

In buildFixItInsertionLine() from

if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos)

to

if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second))

and the output is nice with:

// allSingleDecls contains multiple lines with necessary indentations

auto Diag = diag(declStmt->getSourceRange().getBegin(), “declaration statement can be split up into single line declarations”);
Diag << FixItHint::CreateReplacement(declStmt->getSourceRange(), allSingleDecls);

check-clang and check-clang-tools are reporting no failed tests.