Please use GitHub pull requests for new patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
clang/lib/Format/WhitespaceManager.cpp
//===--- WhitespaceManager.cpp - Format C++ code --------------------------===// | //===--- WhitespaceManager.cpp - Format C++ code --------------------------===// | |||||||||||
// | // | |||||||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||||||||||
// See https://llvm.org/LICENSE.txt for license information. | // See https://llvm.org/LICENSE.txt for license information. | |||||||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||||||||||
// | // | |||||||||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | |||||||||||
/// | /// | |||||||||||
/// \file | /// \file | |||||||||||
/// This file implements WhitespaceManager class. | /// This file implements WhitespaceManager class. | |||||||||||
/// | /// | |||||||||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | |||||||||||
#include "WhitespaceManager.h" | #include "WhitespaceManager.h" | |||||||||||
#include "llvm/ADT/STLExtras.h" | #include "llvm/ADT/STLExtras.h" | |||||||||||
#include "llvm/ADT/SmallVector.h" | #include "llvm/ADT/SmallVector.h" | |||||||||||
#include "llvm/Support/Regex.h" | ||||||||||||
#include <algorithm> | #include <algorithm> | |||||||||||
namespace clang { | namespace clang { | |||||||||||
namespace format { | namespace format { | |||||||||||
bool WhitespaceManager::Change::IsBeforeInFile::operator()( | bool WhitespaceManager::Change::IsBeforeInFile::operator()( | |||||||||||
const Change &C1, const Change &C2) const { | const Change &C1, const Change &C2) const { | |||||||||||
return SourceMgr.isBeforeInTranslationUnit( | return SourceMgr.isBeforeInTranslationUnit( | |||||||||||
▲ Show 20 Lines • Show All 957 Lines • ▼ Show 20 Lines | for (unsigned i = 0, e = Changes.size(); i != e; ++i) { | |||||||||||
// If we don't create a replacement for this change, we have to consider | // If we don't create a replacement for this change, we have to consider | |||||||||||
// it to be immovable. | // it to be immovable. | |||||||||||
if (!Changes[i].CreateReplacement) | if (!Changes[i].CreateReplacement) | |||||||||||
ChangeMaxColumn = ChangeMinColumn; | ChangeMaxColumn = ChangeMinColumn; | |||||||||||
if (i + 1 != e && Changes[i + 1].ContinuesPPDirective) | if (i + 1 != e && Changes[i + 1].ContinuesPPDirective) | |||||||||||
ChangeMaxColumn -= 2; | ChangeMaxColumn -= 2; | |||||||||||
// If this comment follows an } in column 0, it probably documents the | ||||||||||||
// closing of a namespace and we don't want to align it. | // Check if a given comment is most likely a comment to end a namespace. | |||||||||||
bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 && | auto IsNamespaceComment = [this](llvm::StringRef CommentText) { | |||||||||||
// The Regex is a subset of what is defined in | ||||||||||||
owenpan: Don't we still need to check `Changes[i].NewlinesBefore == 0`? How would this format the code… | ||||||||||||
Will check. HazardyKnusperkeks: Will check. | ||||||||||||
// NamespaceEndCommentsFixer.cpp validEndComment(). | ||||||||||||
To minimize the diff. owenpan: To minimize the diff. | ||||||||||||
static const llvm::Regex NamespaceCommentRegex( | ||||||||||||
"// *(end (of )?)? *(anonymous|unnamed)? *(namespace|[A-Za-z0-9_]+)", | ||||||||||||
llvm::Regex::IgnoreCase); | ||||||||||||
SmallVector<StringRef, 5> Groups; | ||||||||||||
auto Matched = NamespaceCommentRegex.match(CommentText, &Groups); | ||||||||||||
if (!Matched) | ||||||||||||
return false; | ||||||||||||
assert(Groups.size() > 4); | ||||||||||||
StringRef NamespaceText = Groups[4]; | ||||||||||||
return NamespaceText.equals_insensitive("namespace") || | ||||||||||||
llvm::is_contained(Style.NamespaceMacros, NamespaceText); | ||||||||||||
}; | ||||||||||||
// We don't want to align namespace end comments. To detect that we check | ||||||||||||
// that the comments follows a closing brace, and its comment matches our | ||||||||||||
// heuristic. | ||||||||||||
bool DontAlignThisComment = i > 0 && Changes[i].NewlinesBefore == 0 && | ||||||||||||
Changes[i - 1].Tok->is(tok::r_brace) && | Changes[i - 1].Tok->is(tok::r_brace) && | |||||||||||
Changes[i - 1].StartOfTokenColumn == 0; | IsNamespaceComment(Changes[i].Tok->TokenText); | |||||||||||
bool WasAlignedWithStartOfNextLine = false; | bool WasAlignedWithStartOfNextLine = false; | |||||||||||
if (Changes[i].NewlinesBefore >= 1) { // A comment on its own line. | if (Changes[i].NewlinesBefore >= 1) { // A comment on its own line. | |||||||||||
unsigned CommentColumn = SourceMgr.getSpellingColumnNumber( | unsigned CommentColumn = SourceMgr.getSpellingColumnNumber( | |||||||||||
Changes[i].OriginalWhitespaceRange.getEnd()); | Changes[i].OriginalWhitespaceRange.getEnd()); | |||||||||||
for (unsigned j = i + 1; j != e; ++j) { | for (unsigned j = i + 1; j != e; ++j) { | |||||||||||
if (Changes[j].Tok->is(tok::comment)) | if (Changes[j].Tok->is(tok::comment)) | |||||||||||
continue; | continue; | |||||||||||
unsigned NextColumn = SourceMgr.getSpellingColumnNumber( | unsigned NextColumn = SourceMgr.getSpellingColumnNumber( | |||||||||||
Changes[j].OriginalWhitespaceRange.getEnd()); | Changes[j].OriginalWhitespaceRange.getEnd()); | |||||||||||
// The start of the next token was previously aligned with the | // The start of the next token was previously aligned with the | |||||||||||
// start of this comment. | // start of this comment. | |||||||||||
WasAlignedWithStartOfNextLine = | WasAlignedWithStartOfNextLine = | |||||||||||
CommentColumn == NextColumn || | CommentColumn == NextColumn || | |||||||||||
CommentColumn == NextColumn + Style.IndentWidth; | CommentColumn == NextColumn + Style.IndentWidth; | |||||||||||
break; | break; | |||||||||||
} | } | |||||||||||
} | } | |||||||||||
if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Never || | if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Never || | |||||||||||
FollowsRBraceInColumn0) { | DontAlignThisComment) { | |||||||||||
alignTrailingComments(StartOfSequence, i, MinColumn); | alignTrailingComments(StartOfSequence, i, MinColumn); | |||||||||||
MinColumn = ChangeMinColumn; | MinColumn = ChangeMinColumn; | |||||||||||
MaxColumn = ChangeMinColumn; | MaxColumn = ChangeMinColumn; | |||||||||||
StartOfSequence = i; | StartOfSequence = i; | |||||||||||
} else if (BreakBeforeNext || Newlines > NewLineThreshold || | } else if (BreakBeforeNext || Newlines > NewLineThreshold || | |||||||||||
(ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) || | (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) || | |||||||||||
// Break the comment sequence if the previous line did not end | // Break the comment sequence if the previous line did not end | |||||||||||
// in a trailing comment. | // in a trailing comment. | |||||||||||
▲ Show 20 Lines • Show All 534 Lines • Show Last 20 Lines |
Don't we still need to check Changes[i].NewlinesBefore == 0? How would this format the code below with FixNamespaceComments: false?