WhitespaceManager.cpp revision 251662
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 if (NewLines > 0) 25 alignEscapedNewlines(); 26 27 // 2+ newlines mean an empty line separating logic scopes. 28 if (NewLines >= 2) 29 alignComments(); 30 31 // Align line comments if they are trailing or if they continue other 32 // trailing comments. 33 if (Tok.isTrailingComment()) { 34 SourceLocation TokenEndLoc = Tok.FormatTok.getStartOfNonWhitespace() 35 .getLocWithOffset(Tok.FormatTok.TokenLength); 36 // Remove the comment's trailing whitespace. 37 if (Tok.FormatTok.TrailingWhiteSpaceLength != 0) 38 Replaces.insert(tooling::Replacement( 39 SourceMgr, TokenEndLoc, Tok.FormatTok.TrailingWhiteSpaceLength, "")); 40 41 bool LineExceedsColumnLimit = 42 Spaces + WhitespaceStartColumn + Tok.FormatTok.TokenLength > 43 Style.ColumnLimit; 44 // Align comment with other comments. 45 if ((Tok.Parent != NULL || !Comments.empty()) && 46 !LineExceedsColumnLimit) { 47 unsigned MinColumn = 48 NewLines > 0 ? Spaces : WhitespaceStartColumn + Spaces; 49 unsigned MaxColumn = Style.ColumnLimit - Tok.FormatTok.TokenLength; 50 Comments.push_back(StoredToken( 51 Tok.FormatTok.WhiteSpaceStart, Tok.FormatTok.WhiteSpaceLength, 52 MinColumn, MaxColumn, NewLines, Spaces)); 53 return; 54 } 55 } 56 57 // If this line does not have a trailing comment, align the stored comments. 58 if (Tok.Children.empty() && !Tok.isTrailingComment()) 59 alignComments(); 60 61 storeReplacement(Tok.FormatTok.WhiteSpaceStart, 62 Tok.FormatTok.WhiteSpaceLength, 63 getNewLineText(NewLines, Spaces)); 64} 65 66void WhitespaceManager::replacePPWhitespace(const AnnotatedToken &Tok, 67 unsigned NewLines, unsigned Spaces, 68 unsigned WhitespaceStartColumn) { 69 if (NewLines == 0) { 70 replaceWhitespace(Tok, NewLines, Spaces, WhitespaceStartColumn); 71 } else { 72 // The earliest position for "\" is 2 after the last token. 73 unsigned MinColumn = WhitespaceStartColumn + 2; 74 unsigned MaxColumn = Style.ColumnLimit; 75 EscapedNewlines.push_back(StoredToken( 76 Tok.FormatTok.WhiteSpaceStart, Tok.FormatTok.WhiteSpaceLength, 77 MinColumn, MaxColumn, NewLines, Spaces)); 78 } 79} 80 81void WhitespaceManager::breakToken(const FormatToken &Tok, unsigned Offset, 82 unsigned ReplaceChars, StringRef Prefix, 83 StringRef Postfix, bool InPPDirective, 84 unsigned Spaces, 85 unsigned WhitespaceStartColumn) { 86 SourceLocation Location = 87 Tok.getStartOfNonWhitespace().getLocWithOffset(Offset); 88 if (InPPDirective) { 89 // The earliest position for "\" is 2 after the last token. 90 unsigned MinColumn = WhitespaceStartColumn + 2; 91 unsigned MaxColumn = Style.ColumnLimit; 92 StoredToken StoredTok = StoredToken(Location, ReplaceChars, MinColumn, 93 MaxColumn, /*NewLines=*/ 1, Spaces); 94 StoredTok.Prefix = Prefix; 95 StoredTok.Postfix = Postfix; 96 EscapedNewlines.push_back(StoredTok); 97 } else { 98 std::string ReplacementText = 99 (Prefix + getNewLineText(1, Spaces) + Postfix).str(); 100 Replaces.insert(tooling::Replacement(SourceMgr, Location, ReplaceChars, 101 ReplacementText)); 102 } 103} 104 105const tooling::Replacements &WhitespaceManager::generateReplacements() { 106 alignComments(); 107 alignEscapedNewlines(); 108 return Replaces; 109} 110 111void WhitespaceManager::addReplacement(const SourceLocation &SourceLoc, 112 unsigned ReplaceChars, StringRef Text) { 113 Replaces.insert( 114 tooling::Replacement(SourceMgr, SourceLoc, ReplaceChars, Text)); 115} 116 117void WhitespaceManager::addUntouchableComment(unsigned Column) { 118 StoredToken Tok = StoredToken(SourceLocation(), 0, Column, Column, 0, 0); 119 Tok.Untouchable = true; 120 Comments.push_back(Tok); 121} 122 123std::string WhitespaceManager::getNewLineText(unsigned NewLines, 124 unsigned Spaces) { 125 return std::string(NewLines, '\n') + std::string(Spaces, ' '); 126} 127 128std::string WhitespaceManager::getNewLineText(unsigned NewLines, 129 unsigned Spaces, 130 unsigned WhitespaceStartColumn, 131 unsigned EscapedNewlineColumn) { 132 std::string NewLineText; 133 if (NewLines > 0) { 134 unsigned Offset = 135 std::min<int>(EscapedNewlineColumn - 1, WhitespaceStartColumn); 136 for (unsigned i = 0; i < NewLines; ++i) { 137 NewLineText += std::string(EscapedNewlineColumn - Offset - 1, ' '); 138 NewLineText += "\\\n"; 139 Offset = 0; 140 } 141 } 142 return NewLineText + std::string(Spaces, ' '); 143} 144 145void WhitespaceManager::alignComments() { 146 unsigned MinColumn = 0; 147 unsigned MaxColumn = UINT_MAX; 148 token_iterator Start = Comments.begin(); 149 for (token_iterator I = Start, E = Comments.end(); I != E; ++I) { 150 if (I->MinColumn > MaxColumn || I->MaxColumn < MinColumn) { 151 alignComments(Start, I, MinColumn); 152 MinColumn = I->MinColumn; 153 MaxColumn = I->MaxColumn; 154 Start = I; 155 } else { 156 MinColumn = std::max(MinColumn, I->MinColumn); 157 MaxColumn = std::min(MaxColumn, I->MaxColumn); 158 } 159 } 160 alignComments(Start, Comments.end(), MinColumn); 161 Comments.clear(); 162} 163 164void WhitespaceManager::alignComments(token_iterator I, token_iterator E, 165 unsigned Column) { 166 while (I != E) { 167 if (!I->Untouchable) { 168 unsigned Spaces = I->Spaces + Column - I->MinColumn; 169 storeReplacement(I->ReplacementLoc, I->ReplacementLength, 170 getNewLineText(I->NewLines, Spaces)); 171 } 172 ++I; 173 } 174} 175 176void WhitespaceManager::alignEscapedNewlines() { 177 unsigned MinColumn; 178 if (Style.AlignEscapedNewlinesLeft) { 179 MinColumn = 0; 180 for (token_iterator I = EscapedNewlines.begin(), E = EscapedNewlines.end(); 181 I != E; ++I) { 182 if (I->MinColumn > MinColumn) 183 MinColumn = I->MinColumn; 184 } 185 } else { 186 MinColumn = Style.ColumnLimit; 187 } 188 189 for (token_iterator I = EscapedNewlines.begin(), E = EscapedNewlines.end(); 190 I != E; ++I) { 191 // I->MinColumn - 2 is the end of the previous token (i.e. the 192 // WhitespaceStartColumn). 193 storeReplacement( 194 I->ReplacementLoc, I->ReplacementLength, 195 I->Prefix + getNewLineText(I->NewLines, I->Spaces, I->MinColumn - 2, 196 MinColumn) + I->Postfix); 197 198 } 199 EscapedNewlines.clear(); 200} 201 202void WhitespaceManager::storeReplacement(SourceLocation Loc, unsigned Length, 203 const std::string Text) { 204 // Don't create a replacement, if it does not change anything. 205 if (StringRef(SourceMgr.getCharacterData(Loc), Length) == Text) 206 return; 207 Replaces.insert(tooling::Replacement(SourceMgr, Loc, Length, Text)); 208} 209 210} // namespace format 211} // namespace clang 212