aboutsummaryrefslogtreecommitdiff
path: root/lib/Frontend/TextDiagnostic.cpp
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2012-07-16 20:52:12 +0000
committerJordan Rose <jordan_rose@apple.com>2012-07-16 20:52:12 +0000
commit6f977c3e7918f9a668164f3ce27f1baa9557eb82 (patch)
tree1a45c49bbc08bba0d9bb3858f58ad76976ece0e6 /lib/Frontend/TextDiagnostic.cpp
parent980343b9a1d0e85f960fa289c2c9a727004964f2 (diff)
Don't crash when emitting fixits following Unicode characters.
This code is very sensitive to the difference between "columns" as printed and "bytes" (SourceManager columns). All variables are now named explicitly and our assumptions are (hopefully) documented as both comment and assertion. Whether parseable fixits should use byte offsets or Unicode character counts is pending discussion on the mailing list; currently the implementation uses bytes (and has no problems on lines containing multibyte characters). This has been added to the user manual. <rdar://problem/11877454> git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160319 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Frontend/TextDiagnostic.cpp')
-rw-r--r--lib/Frontend/TextDiagnostic.cpp53
1 files changed, 26 insertions, 27 deletions
diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp
index 306306d3ac..f604f8aa57 100644
--- a/lib/Frontend/TextDiagnostic.cpp
+++ b/lib/Frontend/TextDiagnostic.cpp
@@ -1124,7 +1124,7 @@ std::string TextDiagnostic::buildFixItInsertionLine(
std::string FixItInsertionLine;
if (Hints.empty() || !DiagOpts.ShowFixits)
return FixItInsertionLine;
- unsigned PrevHintEnd = 0;
+ unsigned PrevHintEndCol = 0;
for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
I != E; ++I) {
@@ -1136,11 +1136,15 @@ std::string TextDiagnostic::buildFixItInsertionLine(
if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second)) {
// Insert the new code into the line just below the code
// that the user wrote.
- unsigned HintColNo
+ // Note: When modifying this function, be very careful about what is a
+ // "column" (printed width, platform-dependent) and what is a
+ // "byte offset" (SourceManager "column").
+ unsigned HintByteOffset
= SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1;
- // hint must start inside the source or right at the end
- assert(HintColNo<static_cast<unsigned>(map.bytes())+1);
- HintColNo = map.byteToColumn(HintColNo);
+
+ // The hint must start inside the source or right at the end
+ assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1);
+ unsigned HintCol = map.byteToColumn(HintByteOffset);
// If we inserted a long previous hint, push this one forwards, and add
// an extra space to show that this is not part of the previous
@@ -1149,32 +1153,27 @@ std::string TextDiagnostic::buildFixItInsertionLine(
//
// Note that if this hint is located immediately after the previous
// hint, no space will be added, since the location is more important.
- if (HintColNo < PrevHintEnd)
- HintColNo = PrevHintEnd + 1;
-
- // FIXME: if the fixit includes tabs or other characters that do not
- // take up a single column per byte when displayed then
- // I->CodeToInsert.size() is not a column number and we're mixing
- // units (columns + bytes). We should get printable versions
- // of each fixit before using them.
- unsigned LastColumnModified
- = HintColNo + I->CodeToInsert.size();
-
- if (LastColumnModified <= static_cast<unsigned>(map.bytes())) {
- // If we're right in the middle of a multibyte character skip to
- // the end of it.
- while (map.byteToColumn(LastColumnModified) == -1)
- ++LastColumnModified;
- LastColumnModified = map.byteToColumn(LastColumnModified);
- }
-
+ if (HintCol < PrevHintEndCol)
+ HintCol = PrevHintEndCol + 1;
+
+ // FIXME: This function handles multibyte characters in the source, but
+ // not in the fixits. This assertion is intended to catch unintended
+ // use of multibyte characters in fixits. If we decide to do this, we'll
+ // have to track separate byte widths for the source and fixit lines.
+ assert((size_t)llvm::sys::locale::columnWidth(I->CodeToInsert) ==
+ I->CodeToInsert.size());
+
+ // This relies on one byte per column in our fixit hints.
+ // This should NOT use HintByteOffset, because the source might have
+ // Unicode characters in earlier columns.
+ unsigned LastColumnModified = HintCol + I->CodeToInsert.size();
if (LastColumnModified > FixItInsertionLine.size())
FixItInsertionLine.resize(LastColumnModified, ' ');
- assert(HintColNo+I->CodeToInsert.size() <= FixItInsertionLine.size());
+
std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
- FixItInsertionLine.begin() + HintColNo);
+ FixItInsertionLine.begin() + HintCol);
- PrevHintEnd = LastColumnModified;
+ PrevHintEndCol = LastColumnModified;
} else {
FixItInsertionLine.clear();
break;