1 1.1 joerg //===--- AffectedRangeManager.cpp - Format C++ code -----------------------===// 2 1.1 joerg // 3 1.1 joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 1.1 joerg // See https://llvm.org/LICENSE.txt for license information. 5 1.1 joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 1.1 joerg // 7 1.1 joerg //===----------------------------------------------------------------------===// 8 1.1 joerg /// 9 1.1 joerg /// \file 10 1.1 joerg /// This file implements AffectRangeManager class. 11 1.1 joerg /// 12 1.1 joerg //===----------------------------------------------------------------------===// 13 1.1 joerg 14 1.1 joerg #include "AffectedRangeManager.h" 15 1.1 joerg 16 1.1 joerg #include "FormatToken.h" 17 1.1 joerg #include "TokenAnnotator.h" 18 1.1 joerg 19 1.1 joerg namespace clang { 20 1.1 joerg namespace format { 21 1.1 joerg 22 1.1 joerg bool AffectedRangeManager::computeAffectedLines( 23 1.1 joerg SmallVectorImpl<AnnotatedLine *> &Lines) { 24 1.1 joerg SmallVectorImpl<AnnotatedLine *>::iterator I = Lines.begin(); 25 1.1 joerg SmallVectorImpl<AnnotatedLine *>::iterator E = Lines.end(); 26 1.1 joerg bool SomeLineAffected = false; 27 1.1 joerg const AnnotatedLine *PreviousLine = nullptr; 28 1.1 joerg while (I != E) { 29 1.1 joerg AnnotatedLine *Line = *I; 30 1.1 joerg Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First); 31 1.1 joerg 32 1.1 joerg // If a line is part of a preprocessor directive, it needs to be formatted 33 1.1 joerg // if any token within the directive is affected. 34 1.1 joerg if (Line->InPPDirective) { 35 1.1 joerg FormatToken *Last = Line->Last; 36 1.1 joerg SmallVectorImpl<AnnotatedLine *>::iterator PPEnd = I + 1; 37 1.1 joerg while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) { 38 1.1 joerg Last = (*PPEnd)->Last; 39 1.1 joerg ++PPEnd; 40 1.1 joerg } 41 1.1 joerg 42 1.1 joerg if (affectsTokenRange(*Line->First, *Last, 43 1.1 joerg /*IncludeLeadingNewlines=*/false)) { 44 1.1 joerg SomeLineAffected = true; 45 1.1 joerg markAllAsAffected(I, PPEnd); 46 1.1 joerg } 47 1.1 joerg I = PPEnd; 48 1.1 joerg continue; 49 1.1 joerg } 50 1.1 joerg 51 1.1 joerg if (nonPPLineAffected(Line, PreviousLine, Lines)) 52 1.1 joerg SomeLineAffected = true; 53 1.1 joerg 54 1.1 joerg PreviousLine = Line; 55 1.1 joerg ++I; 56 1.1 joerg } 57 1.1 joerg return SomeLineAffected; 58 1.1 joerg } 59 1.1 joerg 60 1.1 joerg bool AffectedRangeManager::affectsCharSourceRange( 61 1.1 joerg const CharSourceRange &Range) { 62 1.1 joerg for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(), 63 1.1 joerg E = Ranges.end(); 64 1.1 joerg I != E; ++I) { 65 1.1 joerg if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) && 66 1.1 joerg !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin())) 67 1.1 joerg return true; 68 1.1 joerg } 69 1.1 joerg return false; 70 1.1 joerg } 71 1.1 joerg 72 1.1 joerg bool AffectedRangeManager::affectsTokenRange(const FormatToken &First, 73 1.1 joerg const FormatToken &Last, 74 1.1 joerg bool IncludeLeadingNewlines) { 75 1.1 joerg SourceLocation Start = First.WhitespaceRange.getBegin(); 76 1.1 joerg if (!IncludeLeadingNewlines) 77 1.1 joerg Start = Start.getLocWithOffset(First.LastNewlineOffset); 78 1.1 joerg SourceLocation End = Last.getStartOfNonWhitespace(); 79 1.1 joerg End = End.getLocWithOffset(Last.TokenText.size()); 80 1.1 joerg CharSourceRange Range = CharSourceRange::getCharRange(Start, End); 81 1.1 joerg return affectsCharSourceRange(Range); 82 1.1 joerg } 83 1.1 joerg 84 1.1 joerg bool AffectedRangeManager::affectsLeadingEmptyLines(const FormatToken &Tok) { 85 1.1 joerg CharSourceRange EmptyLineRange = CharSourceRange::getCharRange( 86 1.1 joerg Tok.WhitespaceRange.getBegin(), 87 1.1 joerg Tok.WhitespaceRange.getBegin().getLocWithOffset(Tok.LastNewlineOffset)); 88 1.1 joerg return affectsCharSourceRange(EmptyLineRange); 89 1.1 joerg } 90 1.1 joerg 91 1.1 joerg void AffectedRangeManager::markAllAsAffected( 92 1.1 joerg SmallVectorImpl<AnnotatedLine *>::iterator I, 93 1.1 joerg SmallVectorImpl<AnnotatedLine *>::iterator E) { 94 1.1 joerg while (I != E) { 95 1.1 joerg (*I)->Affected = true; 96 1.1 joerg markAllAsAffected((*I)->Children.begin(), (*I)->Children.end()); 97 1.1 joerg ++I; 98 1.1 joerg } 99 1.1 joerg } 100 1.1 joerg 101 1.1 joerg bool AffectedRangeManager::nonPPLineAffected( 102 1.1 joerg AnnotatedLine *Line, const AnnotatedLine *PreviousLine, 103 1.1 joerg SmallVectorImpl<AnnotatedLine *> &Lines) { 104 1.1 joerg bool SomeLineAffected = false; 105 1.1 joerg Line->ChildrenAffected = computeAffectedLines(Line->Children); 106 1.1 joerg if (Line->ChildrenAffected) 107 1.1 joerg SomeLineAffected = true; 108 1.1 joerg 109 1.1 joerg // Stores whether one of the line's tokens is directly affected. 110 1.1 joerg bool SomeTokenAffected = false; 111 1.1 joerg // Stores whether we need to look at the leading newlines of the next token 112 1.1 joerg // in order to determine whether it was affected. 113 1.1 joerg bool IncludeLeadingNewlines = false; 114 1.1 joerg 115 1.1 joerg // Stores whether the first child line of any of this line's tokens is 116 1.1 joerg // affected. 117 1.1 joerg bool SomeFirstChildAffected = false; 118 1.1 joerg 119 1.1 joerg for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) { 120 1.1 joerg // Determine whether 'Tok' was affected. 121 1.1 joerg if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines)) 122 1.1 joerg SomeTokenAffected = true; 123 1.1 joerg 124 1.1 joerg // Determine whether the first child of 'Tok' was affected. 125 1.1 joerg if (!Tok->Children.empty() && Tok->Children.front()->Affected) 126 1.1 joerg SomeFirstChildAffected = true; 127 1.1 joerg 128 1.1 joerg IncludeLeadingNewlines = Tok->Children.empty(); 129 1.1 joerg } 130 1.1 joerg 131 1.1 joerg // Was this line moved, i.e. has it previously been on the same line as an 132 1.1 joerg // affected line? 133 1.1 joerg bool LineMoved = PreviousLine && PreviousLine->Affected && 134 1.1 joerg Line->First->NewlinesBefore == 0; 135 1.1 joerg 136 1.1 joerg bool IsContinuedComment = 137 1.1 joerg Line->First->is(tok::comment) && Line->First->Next == nullptr && 138 1.1 joerg Line->First->NewlinesBefore < 2 && PreviousLine && 139 1.1 joerg PreviousLine->Affected && PreviousLine->Last->is(tok::comment); 140 1.1 joerg 141 1.1 joerg bool IsAffectedClosingBrace = 142 1.1 joerg Line->First->is(tok::r_brace) && 143 1.1 joerg Line->MatchingOpeningBlockLineIndex != UnwrappedLine::kInvalidIndex && 144 1.1 joerg Lines[Line->MatchingOpeningBlockLineIndex]->Affected; 145 1.1 joerg 146 1.1 joerg if (SomeTokenAffected || SomeFirstChildAffected || LineMoved || 147 1.1 joerg IsContinuedComment || IsAffectedClosingBrace) { 148 1.1 joerg Line->Affected = true; 149 1.1 joerg SomeLineAffected = true; 150 1.1 joerg } 151 1.1 joerg return SomeLineAffected; 152 1.1 joerg } 153 1.1 joerg 154 1.1 joerg } // namespace format 155 1.1 joerg } // namespace clang 156