Path: blob/main/contrib/llvm-project/clang/lib/Format/TokenAnnotator.h
35233 views
//===--- TokenAnnotator.h - Format C++ code ---------------------*- C++ -*-===//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 a token annotator, i.e. creates10/// \c AnnotatedTokens out of \c FormatTokens with required extra information.11///12//===----------------------------------------------------------------------===//1314#ifndef LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H15#define LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H1617#include "UnwrappedLineParser.h"1819namespace clang {20namespace format {2122enum LineType {23LT_Invalid,24// Contains public/private/protected followed by TT_InheritanceColon.25LT_AccessModifier,26LT_ImportStatement,27LT_ObjCDecl, // An @interface, @implementation, or @protocol line.28LT_ObjCMethodDecl,29LT_ObjCProperty, // An @property line.30LT_Other,31LT_PreprocessorDirective,32LT_VirtualFunctionDecl,33LT_ArrayOfStructInitializer,34LT_CommentAbovePPDirective,35};3637enum ScopeType {38// Contained in class declaration/definition.39ST_Class,40// Contained within function definition.41ST_Function,42// Contained within other scope block (loop, if/else, etc).43ST_Other,44};4546class AnnotatedLine {47public:48AnnotatedLine(const UnwrappedLine &Line)49: First(Line.Tokens.front().Tok), Type(LT_Other), Level(Line.Level),50PPLevel(Line.PPLevel),51MatchingOpeningBlockLineIndex(Line.MatchingOpeningBlockLineIndex),52MatchingClosingBlockLineIndex(Line.MatchingClosingBlockLineIndex),53InPPDirective(Line.InPPDirective),54InPragmaDirective(Line.InPragmaDirective),55InMacroBody(Line.InMacroBody),56MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),57IsMultiVariableDeclStmt(false), Affected(false),58LeadingEmptyLinesAffected(false), ChildrenAffected(false),59ReturnTypeWrapped(false), IsContinuation(Line.IsContinuation),60FirstStartColumn(Line.FirstStartColumn) {61assert(!Line.Tokens.empty());6263// Calculate Next and Previous for all tokens. Note that we must overwrite64// Next and Previous for every token, as previous formatting runs might have65// left them in a different state.66First->Previous = nullptr;67FormatToken *Current = First;68addChildren(Line.Tokens.front(), Current);69for (const UnwrappedLineNode &Node : llvm::drop_begin(Line.Tokens)) {70if (Node.Tok->MacroParent)71ContainsMacroCall = true;72Current->Next = Node.Tok;73Node.Tok->Previous = Current;74Current = Current->Next;75addChildren(Node, Current);76// FIXME: if we add children, previous will point to the token before77// the children; changing this requires significant changes across78// clang-format.79}80Last = Current;81Last->Next = nullptr;82}8384void addChildren(const UnwrappedLineNode &Node, FormatToken *Current) {85Current->Children.clear();86for (const auto &Child : Node.Children) {87Children.push_back(new AnnotatedLine(Child));88if (Children.back()->ContainsMacroCall)89ContainsMacroCall = true;90Current->Children.push_back(Children.back());91}92}9394size_t size() const {95size_t Size = 1;96for (const auto *Child : Children)97Size += Child->size();98return Size;99}100101~AnnotatedLine() {102for (AnnotatedLine *Child : Children)103delete Child;104FormatToken *Current = First;105while (Current) {106Current->Children.clear();107Current->Role.reset();108Current = Current->Next;109}110}111112bool isComment() const {113return First && First->is(tok::comment) && !First->getNextNonComment();114}115116/// \c true if this line starts with the given tokens in order, ignoring117/// comments.118template <typename... Ts> bool startsWith(Ts... Tokens) const {119return First && First->startsSequence(Tokens...);120}121122/// \c true if this line ends with the given tokens in reversed order,123/// ignoring comments.124/// For example, given tokens [T1, T2, T3, ...], the function returns true if125/// this line is like "... T3 T2 T1".126template <typename... Ts> bool endsWith(Ts... Tokens) const {127return Last && Last->endsSequence(Tokens...);128}129130/// \c true if this line looks like a function definition instead of a131/// function declaration. Asserts MightBeFunctionDecl.132bool mightBeFunctionDefinition() const {133assert(MightBeFunctionDecl);134// Try to determine if the end of a stream of tokens is either the135// Definition or the Declaration for a function. It does this by looking for136// the ';' in foo(); and using that it ends with a ; to know this is the137// Definition, however the line could end with138// foo(); /* comment */139// or140// foo(); // comment141// or142// foo() // comment143// endsWith() ignores the comment.144return !endsWith(tok::semi);145}146147/// \c true if this line starts a namespace definition.148bool startsWithNamespace() const {149return startsWith(tok::kw_namespace) || startsWith(TT_NamespaceMacro) ||150startsWith(tok::kw_inline, tok::kw_namespace) ||151startsWith(tok::kw_export, tok::kw_namespace);152}153154FormatToken *getFirstNonComment() const {155assert(First);156return First->is(tok::comment) ? First->getNextNonComment() : First;157}158159FormatToken *getLastNonComment() const {160assert(Last);161return Last->is(tok::comment) ? Last->getPreviousNonComment() : Last;162}163164FormatToken *First;165FormatToken *Last;166167SmallVector<AnnotatedLine *, 0> Children;168169LineType Type;170unsigned Level;171unsigned PPLevel;172size_t MatchingOpeningBlockLineIndex;173size_t MatchingClosingBlockLineIndex;174bool InPPDirective;175bool InPragmaDirective;176bool InMacroBody;177bool MustBeDeclaration;178bool MightBeFunctionDecl;179bool IsMultiVariableDeclStmt;180181/// \c True if this line contains a macro call for which an expansion exists.182bool ContainsMacroCall = false;183184/// \c True if this line should be formatted, i.e. intersects directly or185/// indirectly with one of the input ranges.186bool Affected;187188/// \c True if the leading empty lines of this line intersect with one of the189/// input ranges.190bool LeadingEmptyLinesAffected;191192/// \c True if one of this line's children intersects with an input range.193bool ChildrenAffected;194195/// \c True if breaking after last attribute group in function return type.196bool ReturnTypeWrapped;197198/// \c True if this line should be indented by ContinuationIndent in addition199/// to the normal indention level.200bool IsContinuation;201202unsigned FirstStartColumn;203204private:205// Disallow copying.206AnnotatedLine(const AnnotatedLine &) = delete;207void operator=(const AnnotatedLine &) = delete;208};209210/// Determines extra information about the tokens comprising an211/// \c UnwrappedLine.212class TokenAnnotator {213public:214TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)215: Style(Style), IsCpp(Style.isCpp()),216LangOpts(getFormattingLangOpts(Style)), Keywords(Keywords) {217assert(IsCpp == LangOpts.CXXOperatorNames);218}219220/// Adapts the indent levels of comment lines to the indent of the221/// subsequent line.222// FIXME: Can/should this be done in the UnwrappedLineParser?223void setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines) const;224225void annotate(AnnotatedLine &Line);226void calculateFormattingInformation(AnnotatedLine &Line) const;227228private:229/// Calculate the penalty for splitting before \c Tok.230unsigned splitPenalty(const AnnotatedLine &Line, const FormatToken &Tok,231bool InFunctionDecl) const;232233bool spaceRequiredBeforeParens(const FormatToken &Right) const;234235bool spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left,236const FormatToken &Right) const;237238bool spaceRequiredBefore(const AnnotatedLine &Line,239const FormatToken &Right) const;240241bool mustBreakBefore(const AnnotatedLine &Line,242const FormatToken &Right) const;243244bool canBreakBefore(const AnnotatedLine &Line,245const FormatToken &Right) const;246247bool mustBreakForReturnType(const AnnotatedLine &Line) const;248249void printDebugInfo(const AnnotatedLine &Line) const;250251void calculateUnbreakableTailLengths(AnnotatedLine &Line) const;252253void calculateArrayInitializerColumnList(AnnotatedLine &Line) const;254255FormatToken *calculateInitializerColumnList(AnnotatedLine &Line,256FormatToken *CurrentToken,257unsigned Depth) const;258FormatStyle::PointerAlignmentStyle259getTokenReferenceAlignment(const FormatToken &PointerOrReference) const;260261FormatStyle::PointerAlignmentStyle getTokenPointerOrReferenceAlignment(262const FormatToken &PointerOrReference) const;263264const FormatStyle &Style;265266bool IsCpp;267LangOptions LangOpts;268269const AdditionalKeywords &Keywords;270271SmallVector<ScopeType> Scopes;272};273274} // end namespace format275} // end namespace clang276277#endif278279280