diff options
| -rw-r--r-- | clang/lib/Frontend/TextDiagnostic.cpp | 20 | ||||
| -rw-r--r-- | clang/test/Frontend/source-col-map.c | 37 |
2 files changed, 48 insertions, 9 deletions
diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp index 7b25da9b296..bbc99141f07 100644 --- a/clang/lib/Frontend/TextDiagnostic.cpp +++ b/clang/lib/Frontend/TextDiagnostic.cpp @@ -293,14 +293,14 @@ struct SourceColumnMap { /// \brief Map from a byte index to the next byte which starts a column. int startOfNextColumn(int N) const { - assert(0 <= N && N < static_cast<int>(m_columnToByte.size() - 1)); + assert(0 <= N && N < static_cast<int>(m_byteToColumn.size() - 1)); while (byteToColumn(++N) == -1) {} return N; } /// \brief Map from a byte index to the previous byte which starts a column. int startOfPreviousColumn(int N) const { - assert(0 < N && N < static_cast<int>(m_columnToByte.size())); + assert(0 < N && N < static_cast<int>(m_byteToColumn.size())); while (byteToColumn(--N) == -1) {} return N; } @@ -323,9 +323,10 @@ static void selectInterestingSourceRegion(std::string &SourceLine, std::string &FixItInsertionLine, unsigned Columns, const SourceColumnMap &map) { - unsigned MaxColumns = std::max<unsigned>(map.columns(), - std::max(CaretLine.size(), - FixItInsertionLine.size())); + unsigned CaretColumns = CaretLine.size(); + unsigned FixItColumns = llvm::sys::locale::columnWidth(FixItInsertionLine); + unsigned MaxColumns = std::max(static_cast<unsigned>(map.columns()), + std::max(CaretColumns, FixItColumns)); // if the number of columns is less than the desired number we're done if (MaxColumns <= Columns) return; @@ -1110,12 +1111,13 @@ void TextDiagnostic::emitSnippetAndCaret( // Copy the line of code into an std::string for ease of manipulation. std::string SourceLine(LineStart, LineEnd); - // Create a line for the caret that is filled with spaces that is the same - // length as the line of source code. - std::string CaretLine(LineEnd-LineStart, ' '); - + // Build the byte to column map. const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop); + // Create a line for the caret that is filled with spaces that is the same + // number of columns as the line of source code. + std::string CaretLine(sourceColMap.columns(), ' '); + // Highlight all of the characters covered by Ranges with ~ characters. for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); diff --git a/clang/test/Frontend/source-col-map.c b/clang/test/Frontend/source-col-map.c new file mode 100644 index 00000000000..a14023bc82a --- /dev/null +++ b/clang/test/Frontend/source-col-map.c @@ -0,0 +1,37 @@ +// RUN: not %clang_cc1 %s -fsyntax-only -fmessage-length 75 -o /dev/null 2>&1 | FileCheck %s -strict-whitespace + +// Test case for the text diagnostics source column conversion crash. + +// This test case tries to check the error diagnostic message printer, which is +// responsible to create the code snippet shorter than the message-length (in +// number of columns.) +// +// The error diagnostic message printer should be able to handle the non-ascii +// characters without any segmentation fault or assertion failure. If your +// changes to clang frontend crashes this case, it is likely that you are mixing +// column index with byte index which are two totally different concepts. + +// NOTE: This file is encoded in UTF-8 and intentionally contains some +// non-ASCII characters. + +__attribute__((format(printf, 1, 2))) +extern int printf(const char *fmt, ...); + +void test1(Unknown* b); // αααα αααα αααα αααα αααα αααα αααα αααα αααα αααα αααα +// CHECK: unknown type name 'Unknown' +// CHECK-NEXT: void test1(Unknown* b); // αααα αααα αααα αααα αααα αααα αααα ααα... +// CHECK-NEXT: {{^ \^$}} + +void test2(Unknown* b); // αααα αααα αααα αααα αααα αααα αααα αααα αααα + +// CHECK: unknown type name 'Unknown' +// CHECK-NEXT: void test2(Unknown* b); // αααα αααα αααα αααα αααα αααα αααα αααα αααα +// CHECK-NEXT: {{^ \^$}} + +void test3() { + /* αααα αααα αααα αααα αααα αααα αααα αααα αααα αααα */ printf("%d", "s"); +} +// CHECK: format specifies type 'int' but the argument has type 'char *' +// CHECK-NEXT: ...αααα αααα αααα αααα αααα αααα αααα αααα αααα */ printf("%d", "s"); +// CHECK-NEXT: {{^ ~~ \^~~$}} +// CHECK-NEXT: {{^ %s$}} |

