WhitespaceManager.cpp revision 919398bb40d5d643f38b6595f5e8eac641e89d50
1//===--- WhitespaceManager.cpp - Format C++ code --------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9/// 10/// \file 11/// \brief This file implements WhitespaceManager class. 12/// 13//===----------------------------------------------------------------------===// 14 15#include "WhitespaceManager.h" 16#include "llvm/ADT/STLExtras.h" 17 18namespace clang { 19namespace format { 20 21void WhitespaceManager::replaceWhitespace(const AnnotatedToken &Tok, 22 unsigned NewLines, unsigned Spaces, 23 unsigned WhitespaceStartColumn) { 24 // 2+ newlines mean an empty line separating logic scopes. 25 if (NewLines >= 2) 26 alignComments(); 27 28 // Align line comments if they are trailing or if they continue other 29 // trailing comments. 30 if (Tok.isTrailingComment()) { 31 SourceLocation TokenEndLoc = Tok.FormatTok.getStartOfNonWhitespace() 32 .getLocWithOffset(Tok.FormatTok.TokenLength); 33 // Remove the comment's trailing whitespace. 34 if (Tok.FormatTok.TrailingWhiteSpaceLength != 0) 35 Replaces.insert(tooling::Replacement( 36 SourceMgr, TokenEndLoc, Tok.FormatTok.TrailingWhiteSpaceLength, "")); 37 38 bool LineExceedsColumnLimit = 39 Spaces + WhitespaceStartColumn + Tok.FormatTok.TokenLength > 40 Style.ColumnLimit; 41 // Align comment with other comments. 42 if ((Tok.Parent != NULL || !Comments.empty()) && !LineExceedsColumnLimit) { 43 StoredComment Comment; 44 Comment.Tok = Tok.FormatTok; 45 Comment.Spaces = Spaces; 46 Comment.NewLines = NewLines; 47 Comment.MinColumn = 48 NewLines > 0 ? Spaces : WhitespaceStartColumn + Spaces; 49 Comment.MaxColumn = Style.ColumnLimit - Tok.FormatTok.TokenLength; 50 Comment.Untouchable = false; 51 Comments.push_back(Comment); 52 return; 53 } 54 } 55 56 // If this line does not have a trailing comment, align the stored comments. 57 if (Tok.Children.empty() && !Tok.isTrailingComment()) 58 alignComments(); 59 60 storeReplacement(Tok.FormatTok, getNewLineText(NewLines, Spaces)); 61} 62 63void WhitespaceManager::replacePPWhitespace(const AnnotatedToken &Tok, 64 unsigned NewLines, unsigned Spaces, 65 unsigned WhitespaceStartColumn) { 66 storeReplacement(Tok.FormatTok, 67 getNewLineText(NewLines, Spaces, WhitespaceStartColumn)); 68} 69 70void WhitespaceManager::breakToken(const FormatToken &Tok, unsigned Offset, 71 unsigned ReplaceChars, StringRef Prefix, 72 StringRef Postfix, bool InPPDirective, 73 unsigned Spaces, 74 unsigned WhitespaceStartColumn) { 75 std::string NewLineText; 76 if (!InPPDirective) 77 NewLineText = getNewLineText(1, Spaces); 78 else 79 NewLineText = getNewLineText(1, Spaces, WhitespaceStartColumn); 80 std::string ReplacementText = (Prefix + NewLineText + Postfix).str(); 81 SourceLocation Location = 82 Tok.getStartOfNonWhitespace().getLocWithOffset(Offset); 83 Replaces.insert( 84 tooling::Replacement(SourceMgr, Location, ReplaceChars, ReplacementText)); 85} 86 87const tooling::Replacements &WhitespaceManager::generateReplacements() { 88 alignComments(); 89 return Replaces; 90} 91 92void WhitespaceManager::addReplacement(const SourceLocation &SourceLoc, 93 unsigned ReplaceChars, StringRef Text) { 94 Replaces.insert( 95 tooling::Replacement(SourceMgr, SourceLoc, ReplaceChars, Text)); 96} 97 98void WhitespaceManager::addUntouchableComment(unsigned Column) { 99 StoredComment Comment; 100 Comment.MinColumn = Column; 101 Comment.MaxColumn = Column; 102 Comment.Untouchable = true; 103 Comments.push_back(Comment); 104} 105 106std::string WhitespaceManager::getNewLineText(unsigned NewLines, 107 unsigned Spaces) { 108 return std::string(NewLines, '\n') + std::string(Spaces, ' '); 109} 110 111std::string WhitespaceManager::getNewLineText(unsigned NewLines, 112 unsigned Spaces, 113 unsigned WhitespaceStartColumn) { 114 std::string NewLineText; 115 if (NewLines > 0) { 116 unsigned Offset = 117 std::min<int>(Style.ColumnLimit - 1, WhitespaceStartColumn); 118 for (unsigned i = 0; i < NewLines; ++i) { 119 NewLineText += std::string(Style.ColumnLimit - Offset - 1, ' '); 120 NewLineText += "\\\n"; 121 Offset = 0; 122 } 123 } 124 return NewLineText + std::string(Spaces, ' '); 125} 126 127void WhitespaceManager::alignComments() { 128 unsigned MinColumn = 0; 129 unsigned MaxColumn = UINT_MAX; 130 comment_iterator Start = Comments.begin(); 131 for (comment_iterator I = Start, E = Comments.end(); I != E; ++I) { 132 if (I->MinColumn > MaxColumn || I->MaxColumn < MinColumn) { 133 alignComments(Start, I, MinColumn); 134 MinColumn = I->MinColumn; 135 MaxColumn = I->MaxColumn; 136 Start = I; 137 } else { 138 MinColumn = std::max(MinColumn, I->MinColumn); 139 MaxColumn = std::min(MaxColumn, I->MaxColumn); 140 } 141 } 142 alignComments(Start, Comments.end(), MinColumn); 143 Comments.clear(); 144} 145 146void WhitespaceManager::alignComments(comment_iterator I, comment_iterator E, 147 unsigned Column) { 148 while (I != E) { 149 if (!I->Untouchable) { 150 unsigned Spaces = I->Spaces + Column - I->MinColumn; 151 storeReplacement(I->Tok, getNewLineText(I->NewLines, Spaces)); 152 } 153 ++I; 154 } 155} 156 157void WhitespaceManager::storeReplacement(const FormatToken &Tok, 158 const std::string Text) { 159 // Don't create a replacement, if it does not change anything. 160 if (StringRef(SourceMgr.getCharacterData(Tok.WhiteSpaceStart), 161 Tok.WhiteSpaceLength) == Text) 162 return; 163 164 Replaces.insert(tooling::Replacement(SourceMgr, Tok.WhiteSpaceStart, 165 Tok.WhiteSpaceLength, Text)); 166} 167 168} // namespace format 169} // namespace clang 170