Path: blob/main/contrib/llvm-project/clang/lib/Format/AffectedRangeManager.cpp
35233 views
//===--- AffectedRangeManager.cpp - Format C++ code -----------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file implements AffectRangeManager class.10///11//===----------------------------------------------------------------------===//1213#include "AffectedRangeManager.h"1415#include "FormatToken.h"16#include "TokenAnnotator.h"1718namespace clang {19namespace format {2021bool AffectedRangeManager::computeAffectedLines(22SmallVectorImpl<AnnotatedLine *> &Lines) {23SmallVectorImpl<AnnotatedLine *>::iterator I = Lines.begin();24SmallVectorImpl<AnnotatedLine *>::iterator E = Lines.end();25bool SomeLineAffected = false;26const AnnotatedLine *PreviousLine = nullptr;27while (I != E) {28AnnotatedLine *Line = *I;29assert(Line->First);30Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First);3132// If a line is part of a preprocessor directive, it needs to be formatted33// if any token within the directive is affected.34if (Line->InPPDirective) {35FormatToken *Last = Line->Last;36SmallVectorImpl<AnnotatedLine *>::iterator PPEnd = I + 1;37while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) {38Last = (*PPEnd)->Last;39++PPEnd;40}4142if (affectsTokenRange(*Line->First, *Last,43/*IncludeLeadingNewlines=*/false)) {44SomeLineAffected = true;45markAllAsAffected(I, PPEnd);46}47I = PPEnd;48continue;49}5051if (nonPPLineAffected(Line, PreviousLine, Lines))52SomeLineAffected = true;5354PreviousLine = Line;55++I;56}57return SomeLineAffected;58}5960bool AffectedRangeManager::affectsCharSourceRange(61const CharSourceRange &Range) {62for (const CharSourceRange &R : Ranges) {63if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), R.getBegin()) &&64!SourceMgr.isBeforeInTranslationUnit(R.getEnd(), Range.getBegin())) {65return true;66}67}68return false;69}7071bool AffectedRangeManager::affectsTokenRange(const FormatToken &First,72const FormatToken &Last,73bool IncludeLeadingNewlines) {74SourceLocation Start = First.WhitespaceRange.getBegin();75if (!IncludeLeadingNewlines)76Start = Start.getLocWithOffset(First.LastNewlineOffset);77SourceLocation End = Last.getStartOfNonWhitespace();78End = End.getLocWithOffset(Last.TokenText.size());79CharSourceRange Range = CharSourceRange::getCharRange(Start, End);80return affectsCharSourceRange(Range);81}8283bool AffectedRangeManager::affectsLeadingEmptyLines(const FormatToken &Tok) {84CharSourceRange EmptyLineRange = CharSourceRange::getCharRange(85Tok.WhitespaceRange.getBegin(),86Tok.WhitespaceRange.getBegin().getLocWithOffset(Tok.LastNewlineOffset));87return affectsCharSourceRange(EmptyLineRange);88}8990void AffectedRangeManager::markAllAsAffected(91SmallVectorImpl<AnnotatedLine *>::iterator I,92SmallVectorImpl<AnnotatedLine *>::iterator E) {93while (I != E) {94(*I)->Affected = true;95markAllAsAffected((*I)->Children.begin(), (*I)->Children.end());96++I;97}98}99100bool AffectedRangeManager::nonPPLineAffected(101AnnotatedLine *Line, const AnnotatedLine *PreviousLine,102SmallVectorImpl<AnnotatedLine *> &Lines) {103bool SomeLineAffected = false;104Line->ChildrenAffected = computeAffectedLines(Line->Children);105if (Line->ChildrenAffected)106SomeLineAffected = true;107108// Stores whether one of the line's tokens is directly affected.109bool SomeTokenAffected = false;110// Stores whether we need to look at the leading newlines of the next token111// in order to determine whether it was affected.112bool IncludeLeadingNewlines = false;113114// Stores whether the first child line of any of this line's tokens is115// affected.116bool SomeFirstChildAffected = false;117118assert(Line->First);119for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {120// Determine whether 'Tok' was affected.121if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines))122SomeTokenAffected = true;123124// Determine whether the first child of 'Tok' was affected.125if (!Tok->Children.empty() && Tok->Children.front()->Affected)126SomeFirstChildAffected = true;127128IncludeLeadingNewlines = Tok->Children.empty();129}130131// Was this line moved, i.e. has it previously been on the same line as an132// affected line?133bool LineMoved = PreviousLine && PreviousLine->Affected &&134Line->First->NewlinesBefore == 0;135136bool IsContinuedComment =137Line->First->is(tok::comment) && !Line->First->Next &&138Line->First->NewlinesBefore < 2 && PreviousLine &&139PreviousLine->Affected && PreviousLine->Last->is(tok::comment);140141bool IsAffectedClosingBrace =142Line->First->is(tok::r_brace) &&143Line->MatchingOpeningBlockLineIndex != UnwrappedLine::kInvalidIndex &&144Lines[Line->MatchingOpeningBlockLineIndex]->Affected;145146if (SomeTokenAffected || SomeFirstChildAffected || LineMoved ||147IsContinuedComment || IsAffectedClosingBrace) {148Line->Affected = true;149SomeLineAffected = true;150}151return SomeLineAffected;152}153154} // namespace format155} // namespace clang156157158