summaryrefslogtreecommitdiffstats
path: root/clang/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
commitfb12a53d5dd2bf37ed4304a5b01cc67b88d4c26a (patch)
tree64b183b1ed93031b00b7911bb1026de70bd398d0 /clang/lib/Frontend/TextDiagnostic.cpp
parent1f4ff15c91014fa72cbd6c1747b745d2b5911dce (diff)
downloadbcm5719-llvm-fb12a53d5dd2bf37ed4304a5b01cc67b88d4c26a.tar.gz
bcm5719-llvm-fb12a53d5dd2bf37ed4304a5b01cc67b88d4c26a.zip
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> llvm-svn: 160319
Diffstat (limited to 'clang/lib/Frontend/TextDiagnostic.cpp')
-rw-r--r--clang/lib/Frontend/TextDiagnostic.cpp53
1 files changed, 26 insertions, 27 deletions
diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp
index 306306d3ace..f604f8aa570 100644
--- a/clang/lib/Frontend/TextDiagnostic.cpp
+++ b/clang/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;
OpenPOWER on IntegriCloud