//===--- AffectedRangeManager.cpp - Format C++ code -----------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief This file implements AffectRangeManager class. /// //===----------------------------------------------------------------------===// #include "AffectedRangeManager.h" #include "FormatToken.h" #include "TokenAnnotator.h" namespace clang { namespace format { bool AffectedRangeManager::computeAffectedLines( SmallVectorImpl::iterator I, SmallVectorImpl::iterator E) { bool SomeLineAffected = false; const AnnotatedLine *PreviousLine = nullptr; while (I != E) { AnnotatedLine *Line = *I; Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First); // If a line is part of a preprocessor directive, it needs to be formatted // if any token within the directive is affected. if (Line->InPPDirective) { FormatToken *Last = Line->Last; SmallVectorImpl::iterator PPEnd = I + 1; while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) { Last = (*PPEnd)->Last; ++PPEnd; } if (affectsTokenRange(*Line->First, *Last, /*IncludeLeadingNewlines=*/false)) { SomeLineAffected = true; markAllAsAffected(I, PPEnd); } I = PPEnd; continue; } if (nonPPLineAffected(Line, PreviousLine)) SomeLineAffected = true; PreviousLine = Line; ++I; } return SomeLineAffected; } bool AffectedRangeManager::affectsCharSourceRange( const CharSourceRange &Range) { for (SmallVectorImpl::const_iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) && !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin())) return true; } return false; } bool AffectedRangeManager::affectsTokenRange(const FormatToken &First, const FormatToken &Last, bool IncludeLeadingNewlines) { SourceLocation Start = First.WhitespaceRange.getBegin(); if (!IncludeLeadingNewlines) Start = Start.getLocWithOffset(First.LastNewlineOffset); SourceLocation End = Last.getStartOfNonWhitespace(); End = End.getLocWithOffset(Last.TokenText.size()); CharSourceRange Range = CharSourceRange::getCharRange(Start, End); return affectsCharSourceRange(Range); } bool AffectedRangeManager::affectsLeadingEmptyLines(const FormatToken &Tok) { CharSourceRange EmptyLineRange = CharSourceRange::getCharRange( Tok.WhitespaceRange.getBegin(), Tok.WhitespaceRange.getBegin().getLocWithOffset(Tok.LastNewlineOffset)); return affectsCharSourceRange(EmptyLineRange); } void AffectedRangeManager::markAllAsAffected( SmallVectorImpl::iterator I, SmallVectorImpl::iterator E) { while (I != E) { (*I)->Affected = true; markAllAsAffected((*I)->Children.begin(), (*I)->Children.end()); ++I; } } bool AffectedRangeManager::nonPPLineAffected( AnnotatedLine *Line, const AnnotatedLine *PreviousLine) { bool SomeLineAffected = false; Line->ChildrenAffected = computeAffectedLines(Line->Children.begin(), Line->Children.end()); if (Line->ChildrenAffected) SomeLineAffected = true; // Stores whether one of the line's tokens is directly affected. bool SomeTokenAffected = false; // Stores whether we need to look at the leading newlines of the next token // in order to determine whether it was affected. bool IncludeLeadingNewlines = false; // Stores whether the first child line of any of this line's tokens is // affected. bool SomeFirstChildAffected = false; for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) { // Determine whether 'Tok' was affected. if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines)) SomeTokenAffected = true; // Determine whether the first child of 'Tok' was affected. if (!Tok->Children.empty() && Tok->Children.front()->Affected) SomeFirstChildAffected = true; IncludeLeadingNewlines = Tok->Children.empty(); } // Was this line moved, i.e. has it previously been on the same line as an // affected line? bool LineMoved = PreviousLine && PreviousLine->Affected && Line->First->NewlinesBefore == 0; bool IsContinuedComment = Line->First->is(tok::comment) && Line->First->Next == nullptr && Line->First->NewlinesBefore < 2 && PreviousLine && PreviousLine->Affected && PreviousLine->Last->is(tok::comment); if (SomeTokenAffected || SomeFirstChildAffected || LineMoved || IsContinuedComment) { Line->Affected = true; SomeLineAffected = true; } return SomeLineAffected; } } // namespace format } // namespace clang