예제 #1
0
std::string TextDiagnostic::buildFixItInsertionLine(
  unsigned LineNo,
  const SourceColumnMap &map,
  ArrayRef<FixItHint> Hints) {

  std::string FixItInsertionLine;
  if (Hints.empty() || !DiagOpts.ShowFixits)
    return FixItInsertionLine;

  for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
       I != E; ++I) {
    if (!I->CodeToInsert.empty()) {
      // We have an insertion hint. Determine whether the inserted
      // code is on the same line as the caret.
      std::pair<FileID, unsigned> HintLocInfo
        = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
      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
          = 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);

        // 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())) {
          unsigned LastExistingColumn = map.byteToColumn(map.bytes());
          unsigned AddedColumns = LastColumnModified-LastExistingColumn;
          LastColumnModified = LastExistingColumn + AddedColumns;
        } else {
          LastColumnModified = map.byteToColumn(LastColumnModified);
        }

        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);
      } else {
        FixItInsertionLine.clear();
        break;
      }
    }
  }

  expandTabs(FixItInsertionLine, DiagOpts.TabStop);

  return FixItInsertionLine;
}
예제 #2
0
static std::string buildFixItInsertionLine(unsigned LineNo,
                                           const SourceColumnMap &map,
                                           ArrayRef<FixItHint> Hints,
                                           const SourceManager &SM,
                                           const DiagnosticOptions *DiagOpts) {
  std::string FixItInsertionLine;
  if (Hints.empty() || !DiagOpts->ShowFixits)
    return FixItInsertionLine;
  unsigned PrevHintEndCol = 0;

  for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
       I != E; ++I) {
    if (!I->CodeToInsert.empty()) {
      // We have an insertion hint. Determine whether the inserted
      // code contains no newlines and is on the same line as the caret.
      std::pair<FileID, unsigned> HintLocInfo
        = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
      if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
          StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) {
        // Insert the new code into the line just below the code
        // that the user wrote.
        // 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;

        // The hint must start inside the source or right at the end
        assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1);
        unsigned HintCol = map.byteToContainingColumn(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
        // completion. This is sort of the best we can do when two hints appear
        // to overlap.
        //
        // Note that if this hint is located immediately after the previous
        // hint, no space will be added, since the location is more important.
        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, ' ');

        std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
                  FixItInsertionLine.begin() + HintCol);

        PrevHintEndCol = LastColumnModified;
      } else {
        FixItInsertionLine.clear();
        break;
      }
    }
  }

  expandTabs(FixItInsertionLine, DiagOpts->TabStop);

  return FixItInsertionLine;
}