This fixes github issue #57117: If the "QualifierAlignment" option of clang-format is set to anything else but "Leave", the "QualifierAlignmentFixer" pass gets enabled. This pass scales quadratically with the number of preprocessor branches, i.e. with the number of elements in TokenAnalyzer::UnwrappedLines. The reason is that QualifierAlignmentFixer::process() generates the UnwrappedLines, but then QualifierAlignmentFixer::analyze() calls LeftRightQualifierAlignmentFixer::process() several times (once for each qualifier) which again each time generates the UnwrappedLines. This commit gets rid of this double loop by registering the individual LeftRightQualifierAlignmentFixer passes directly in the top most container of passes (local variable "Passes" in reformat()). With this change, the original example in the github issue #57117 now takes only around 3s instead of >300s to format. Since QualifierAlignmentFixer::analyze() got deleted, we also no longer have the code with the NonNoOpFixes. This causes replacements that end up not changing anything to appear in the list of final replacements. There is a unit test to check that this does not happen: QualifierFixerTest.NoOpQualifierReplacements. However, it got broken at some point in time. So this commit fixes the test. To keep the behavior that no no-op replacements should appear from the qualifier fixer, the corresponding code from QualifierAlignmentFixer::analyze() was moved to the top reformat() function. Thus, is now done for **every** replacement of every formatting pass. If no-op replacements are a problem for the qualifier fixer, then it seems to be a good idea to filter them out always. See https://github.com/llvm/llvm-project/issues/57117#issuecomment-1546716934 for some more details. Reviewed By: MyDeveloperDay, HazardyKnusperkeks, owenpan Differential Revision: https://reviews.llvm.org/D153228
84 lines
3.1 KiB
C++
84 lines
3.1 KiB
C++
//===--- LeftRightQualifierAlignmentFixer.h ------------------------------*- C++
|
|
//-*-===//
|
|
//
|
|
// 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 declares LeftRightQualifierAlignmentFixer, a TokenAnalyzer that
|
|
/// enforces either east or west const depending on the style.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_LIB_FORMAT_QUALIFIERALIGNMENTFIXER_H
|
|
#define LLVM_CLANG_LIB_FORMAT_QUALIFIERALIGNMENTFIXER_H
|
|
|
|
#include "TokenAnalyzer.h"
|
|
|
|
namespace clang {
|
|
namespace format {
|
|
|
|
typedef std::function<std::pair<tooling::Replacements, unsigned>(
|
|
const Environment &)>
|
|
AnalyzerPass;
|
|
|
|
void addQualifierAlignmentFixerPasses(const FormatStyle &Style,
|
|
SmallVectorImpl<AnalyzerPass> &Passes);
|
|
|
|
void prepareLeftRightOrderingForQualifierAlignmentFixer(
|
|
const std::vector<std::string> &Order, std::vector<std::string> &LeftOrder,
|
|
std::vector<std::string> &RightOrder,
|
|
std::vector<tok::TokenKind> &Qualifiers);
|
|
|
|
class LeftRightQualifierAlignmentFixer : public TokenAnalyzer {
|
|
std::string Qualifier;
|
|
bool RightAlign;
|
|
SmallVector<tok::TokenKind, 8> QualifierTokens;
|
|
std::vector<tok::TokenKind> ConfiguredQualifierTokens;
|
|
|
|
public:
|
|
LeftRightQualifierAlignmentFixer(
|
|
const Environment &Env, const FormatStyle &Style,
|
|
const std::string &Qualifier,
|
|
const std::vector<tok::TokenKind> &ConfiguredQualifierTokens,
|
|
bool RightAlign);
|
|
|
|
std::pair<tooling::Replacements, unsigned>
|
|
analyze(TokenAnnotator &Annotator,
|
|
SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
|
|
FormatTokenLexer &Tokens) override;
|
|
|
|
static tok::TokenKind getTokenFromQualifier(const std::string &Qualifier);
|
|
|
|
const FormatToken *analyzeRight(const SourceManager &SourceMgr,
|
|
const AdditionalKeywords &Keywords,
|
|
tooling::Replacements &Fixes,
|
|
const FormatToken *Tok,
|
|
const std::string &Qualifier,
|
|
tok::TokenKind QualifierType);
|
|
|
|
const FormatToken *analyzeLeft(const SourceManager &SourceMgr,
|
|
const AdditionalKeywords &Keywords,
|
|
tooling::Replacements &Fixes,
|
|
const FormatToken *Tok,
|
|
const std::string &Qualifier,
|
|
tok::TokenKind QualifierType);
|
|
|
|
// Is the Token a simple or qualifier type
|
|
static bool isQualifierOrType(const FormatToken *Tok);
|
|
static bool
|
|
isConfiguredQualifierOrType(const FormatToken *Tok,
|
|
const std::vector<tok::TokenKind> &Qualifiers);
|
|
|
|
// Is the Token likely a Macro
|
|
static bool isPossibleMacro(const FormatToken *Tok);
|
|
};
|
|
|
|
} // end namespace format
|
|
} // end namespace clang
|
|
|
|
#endif
|