BreakableToken.cpp revision 251609
133965Sjdp//===--- BreakableToken.cpp - Format C++ code -----------------------------===// 238889Sjdp// 333965Sjdp// The LLVM Compiler Infrastructure 433965Sjdp// 533965Sjdp// This file is distributed under the University of Illinois Open Source 633965Sjdp// License. See LICENSE.TXT for details. 733965Sjdp// 833965Sjdp//===----------------------------------------------------------------------===// 933965Sjdp/// 1033965Sjdp/// \file 1133965Sjdp/// \brief Contains implementation of BreakableToken class and classes derived 1233965Sjdp/// from it. 1333965Sjdp/// 1433965Sjdp//===----------------------------------------------------------------------===// 1533965Sjdp 1633965Sjdp#include "BreakableToken.h" 1733965Sjdp#include "llvm/ADT/STLExtras.h" 1833965Sjdp#include <algorithm> 1933965Sjdp 2033965Sjdpnamespace clang { 2133965Sjdpnamespace format { 2233965Sjdp 2333965SjdpBreakableToken::Split BreakableComment::getSplit(unsigned LineIndex, 2433965Sjdp unsigned TailOffset, 2533965Sjdp unsigned ColumnLimit) const { 2633965Sjdp StringRef Text = getLine(LineIndex).substr(TailOffset); 2733965Sjdp unsigned ContentStartColumn = getContentStartColumn(LineIndex, TailOffset); 2833965Sjdp if (ColumnLimit <= ContentStartColumn + 1) 2933965Sjdp return Split(StringRef::npos, 0); 3033965Sjdp 3133965Sjdp unsigned MaxSplit = ColumnLimit - ContentStartColumn + 1; 3233965Sjdp StringRef::size_type SpaceOffset = Text.rfind(' ', MaxSplit); 3333965Sjdp if (SpaceOffset == StringRef::npos || 3433965Sjdp Text.find_last_not_of(' ', SpaceOffset) == StringRef::npos) { 3533965Sjdp SpaceOffset = Text.find(' ', MaxSplit); 3633965Sjdp } 3733965Sjdp if (SpaceOffset != StringRef::npos && SpaceOffset != 0) { 3833965Sjdp StringRef BeforeCut = Text.substr(0, SpaceOffset).rtrim(); 3933965Sjdp StringRef AfterCut = Text.substr(SpaceOffset).ltrim(); 4033965Sjdp return BreakableToken::Split(BeforeCut.size(), 4133965Sjdp AfterCut.begin() - BeforeCut.end()); 4233965Sjdp } 4333965Sjdp return BreakableToken::Split(StringRef::npos, 0); 4433965Sjdp} 4533965Sjdp 4633965Sjdpvoid BreakableComment::insertBreak(unsigned LineIndex, unsigned TailOffset, 4733965Sjdp Split Split, bool InPPDirective, 4833965Sjdp WhitespaceManager &Whitespaces) { 4933965Sjdp StringRef Text = getLine(LineIndex).substr(TailOffset); 5033965Sjdp StringRef AdditionalPrefix = Decoration; 5133965Sjdp if (Text.size() == Split.first + Split.second) { 5233965Sjdp // For all but the last line handle trailing space in trimLine. 5333965Sjdp if (LineIndex < Lines.size() - 1) 5433965Sjdp return; 5533965Sjdp // For the last line we need to break before "*/", but not to add "* ". 5633965Sjdp AdditionalPrefix = ""; 5733965Sjdp } 5833965Sjdp 5933965Sjdp unsigned WhitespaceStartColumn = 6033965Sjdp getContentStartColumn(LineIndex, TailOffset) + Split.first; 6133965Sjdp unsigned BreakOffset = Text.data() - TokenText.data() + Split.first; 6233965Sjdp unsigned CharsToRemove = Split.second; 6333965Sjdp Whitespaces.breakToken(Tok, BreakOffset, CharsToRemove, "", AdditionalPrefix, 6433965Sjdp InPPDirective, IndentAtLineBreak, 6533965Sjdp WhitespaceStartColumn); 6633965Sjdp} 6733965Sjdp 6833965SjdpBreakableBlockComment::BreakableBlockComment(const SourceManager &SourceMgr, 6933965Sjdp const AnnotatedToken &Token, 7033965Sjdp unsigned StartColumn) 7133965Sjdp : BreakableComment(SourceMgr, Token.FormatTok, StartColumn + 2) { 7233965Sjdp assert(TokenText.startswith("/*") && TokenText.endswith("*/")); 7333965Sjdp 7433965Sjdp OriginalStartColumn = 7533965Sjdp SourceMgr.getSpellingColumnNumber(Tok.getStartOfNonWhitespace()) - 1; 7633965Sjdp 7733965Sjdp TokenText.substr(2, TokenText.size() - 4).split(Lines, "\n"); 7833965Sjdp 7933965Sjdp bool NeedsStar = true; 8033965Sjdp CommonPrefixLength = UINT_MAX; 8133965Sjdp if (Lines.size() == 1) { 8233965Sjdp if (Token.Parent == 0) { 8333965Sjdp // Standalone block comments will be aligned and prefixed with *s. 8433965Sjdp CommonPrefixLength = OriginalStartColumn + 1; 8533965Sjdp } else { 8633965Sjdp // Trailing comments can start on arbitrary column, and available 8733965Sjdp // horizontal space can be too small to align consecutive lines with 8833965Sjdp // the first one. We could, probably, align them to current 8933965Sjdp // indentation level, but now we just wrap them without indentation 9033965Sjdp // and stars. 9133965Sjdp CommonPrefixLength = 0; 9233965Sjdp NeedsStar = false; 9333965Sjdp } 9433965Sjdp } else { 9533965Sjdp for (size_t i = 1; i < Lines.size(); ++i) { 9633965Sjdp size_t FirstNonWhitespace = Lines[i].find_first_not_of(" "); 9733965Sjdp if (FirstNonWhitespace != StringRef::npos) { 9833965Sjdp NeedsStar = NeedsStar && (Lines[i][FirstNonWhitespace] == '*'); 9933965Sjdp CommonPrefixLength = 10033965Sjdp std::min<unsigned>(CommonPrefixLength, FirstNonWhitespace); 10133965Sjdp } 10233965Sjdp } 10333965Sjdp } 10433965Sjdp if (CommonPrefixLength == UINT_MAX) 10560484Sobrien CommonPrefixLength = 0; 10633965Sjdp 10733965Sjdp Decoration = NeedsStar ? "* " : ""; 10833965Sjdp 10933965Sjdp IndentAtLineBreak = 11033965Sjdp std::max<int>(StartColumn - OriginalStartColumn + CommonPrefixLength, 0); 11133965Sjdp} 11233965Sjdp 11333965Sjdpvoid BreakableBlockComment::alignLines(WhitespaceManager &Whitespaces) { 11433965Sjdp SourceLocation TokenLoc = Tok.getStartOfNonWhitespace(); 11533965Sjdp int IndentDelta = (StartColumn - 2) - OriginalStartColumn; 11633965Sjdp if (IndentDelta > 0) { 11733965Sjdp std::string WhiteSpace(IndentDelta, ' '); 11833965Sjdp for (size_t i = 1; i < Lines.size(); ++i) { 11933965Sjdp Whitespaces.addReplacement( 12033965Sjdp TokenLoc.getLocWithOffset(Lines[i].data() - TokenText.data()), 0, 12133965Sjdp WhiteSpace); 12233965Sjdp } 12333965Sjdp } else if (IndentDelta < 0) { 12433965Sjdp std::string WhiteSpace(-IndentDelta, ' '); 12533965Sjdp // Check that the line is indented enough. 12633965Sjdp for (size_t i = 1; i < Lines.size(); ++i) { 12733965Sjdp if (!Lines[i].startswith(WhiteSpace)) 12833965Sjdp return; 12933965Sjdp } 13033965Sjdp for (size_t i = 1; i < Lines.size(); ++i) { 13133965Sjdp Whitespaces.addReplacement( 13233965Sjdp TokenLoc.getLocWithOffset(Lines[i].data() - TokenText.data()), 13333965Sjdp -IndentDelta, ""); 13433965Sjdp } 13533965Sjdp } 13633965Sjdp 13733965Sjdp for (unsigned i = 1; i < Lines.size(); ++i) 13833965Sjdp Lines[i] = Lines[i].substr(CommonPrefixLength + Decoration.size()); 13933965Sjdp} 14033965Sjdp 14133965Sjdpvoid BreakableBlockComment::trimLine(unsigned LineIndex, unsigned TailOffset, 14233965Sjdp unsigned InPPDirective, 14333965Sjdp WhitespaceManager &Whitespaces) { 14433965Sjdp if (LineIndex == Lines.size() - 1) 14533965Sjdp return; 14633965Sjdp StringRef Text = Lines[LineIndex].substr(TailOffset); 14733965Sjdp if (!Text.endswith(" ") && !InPPDirective) 14833965Sjdp return; 14933965Sjdp 15033965Sjdp StringRef TrimmedLine = Text.rtrim(); 15133965Sjdp unsigned WhitespaceStartColumn = 15233965Sjdp getLineLengthAfterSplit(LineIndex, TailOffset); 15333965Sjdp unsigned BreakOffset = TrimmedLine.end() - TokenText.data(); 15433965Sjdp unsigned CharsToRemove = Text.size() - TrimmedLine.size() + 1; 15533965Sjdp Whitespaces.breakToken(Tok, BreakOffset, CharsToRemove, "", "", InPPDirective, 15633965Sjdp 0, WhitespaceStartColumn); 15733965Sjdp} 15833965Sjdp 15933965SjdpBreakableLineComment::BreakableLineComment(const SourceManager &SourceMgr, 16033965Sjdp const AnnotatedToken &Token, 16133965Sjdp unsigned StartColumn) 16233965Sjdp : BreakableComment(SourceMgr, Token.FormatTok, StartColumn) { 16333965Sjdp assert(TokenText.startswith("//")); 16433965Sjdp Decoration = getLineCommentPrefix(TokenText); 16533965Sjdp Lines.push_back(TokenText.substr(Decoration.size())); 16633965Sjdp IndentAtLineBreak = StartColumn; 16733965Sjdp this->StartColumn += Decoration.size(); // Start column of the contents. 16833965Sjdp} 16933965Sjdp 17033965SjdpStringRef BreakableLineComment::getLineCommentPrefix(StringRef Comment) { 17133965Sjdp const char *KnownPrefixes[] = { "/// ", "///", "// ", "//" }; 17233965Sjdp for (size_t i = 0; i < llvm::array_lengthof(KnownPrefixes); ++i) 17333965Sjdp if (Comment.startswith(KnownPrefixes[i])) 17433965Sjdp return KnownPrefixes[i]; 17533965Sjdp return ""; 17633965Sjdp} 17733965Sjdp 17833965Sjdp} // namespace format 17933965Sjdp} // namespace clang 18033965Sjdp