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
 |