forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			156 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			156 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===--- AffectedRangeManager.cpp - Format C++ code -----------------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| ///
 | |
| /// \file
 | |
| /// This file implements AffectRangeManager class.
 | |
| ///
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "AffectedRangeManager.h"
 | |
| 
 | |
| #include "FormatToken.h"
 | |
| #include "TokenAnnotator.h"
 | |
| 
 | |
| namespace clang {
 | |
| namespace format {
 | |
| 
 | |
| bool AffectedRangeManager::computeAffectedLines(
 | |
|     SmallVectorImpl<AnnotatedLine *> &Lines) {
 | |
|   SmallVectorImpl<AnnotatedLine *>::iterator I = Lines.begin();
 | |
|   SmallVectorImpl<AnnotatedLine *>::iterator E = Lines.end();
 | |
|   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<AnnotatedLine *>::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, Lines))
 | |
|       SomeLineAffected = true;
 | |
| 
 | |
|     PreviousLine = Line;
 | |
|     ++I;
 | |
|   }
 | |
|   return SomeLineAffected;
 | |
| }
 | |
| 
 | |
| bool AffectedRangeManager::affectsCharSourceRange(
 | |
|     const CharSourceRange &Range) {
 | |
|   for (SmallVectorImpl<CharSourceRange>::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<AnnotatedLine *>::iterator I,
 | |
|     SmallVectorImpl<AnnotatedLine *>::iterator E) {
 | |
|   while (I != E) {
 | |
|     (*I)->Affected = true;
 | |
|     markAllAsAffected((*I)->Children.begin(), (*I)->Children.end());
 | |
|     ++I;
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool AffectedRangeManager::nonPPLineAffected(
 | |
|     AnnotatedLine *Line, const AnnotatedLine *PreviousLine,
 | |
|     SmallVectorImpl<AnnotatedLine *> &Lines) {
 | |
|   bool SomeLineAffected = false;
 | |
|   Line->ChildrenAffected = computeAffectedLines(Line->Children);
 | |
|   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);
 | |
| 
 | |
|   bool IsAffectedClosingBrace =
 | |
|       Line->First->is(tok::r_brace) &&
 | |
|       Line->MatchingOpeningBlockLineIndex != UnwrappedLine::kInvalidIndex &&
 | |
|       Lines[Line->MatchingOpeningBlockLineIndex]->Affected;
 | |
| 
 | |
|   if (SomeTokenAffected || SomeFirstChildAffected || LineMoved ||
 | |
|       IsContinuedComment || IsAffectedClosingBrace) {
 | |
|     Line->Affected = true;
 | |
|     SomeLineAffected = true;
 | |
|   }
 | |
|   return SomeLineAffected;
 | |
| }
 | |
| 
 | |
| } // namespace format
 | |
| } // namespace clang
 |