Index: clang-tidy/misc/SwappedArgumentsCheck.cpp =================================================================== --- clang-tidy/misc/SwappedArgumentsCheck.cpp +++ clang-tidy/misc/SwappedArgumentsCheck.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "SwappedArgumentsCheck.h" +#include "../utils/FixItHintUtils.h" #include "clang/AST/ASTContext.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/SmallPtrSet.h" @@ -46,25 +47,9 @@ Cast->getCastKind() == CK_PointerToBoolean; } -/// \brief Get a StringRef representing a SourceRange. -static StringRef getAsString(const MatchFinder::MatchResult &Result, - SourceRange R) { - const SourceManager &SM = *Result.SourceManager; - // Don't even try to resolve macro or include contraptions. Not worth emitting - // a fixit for. - if (R.getBegin().isMacroID() || - !SM.isWrittenInSameFile(R.getBegin(), R.getEnd())) - return StringRef(); - - const char *Begin = SM.getCharacterData(R.getBegin()); - const char *End = SM.getCharacterData(Lexer::getLocForEndOfToken( - R.getEnd(), 0, SM, Result.Context->getLangOpts())); - - return StringRef(Begin, End - Begin); -} - void SwappedArgumentsCheck::check(const MatchFinder::MatchResult &Result) { - auto *Call = Result.Nodes.getStmtAs("call"); + const ASTContext &Ctx = *Result.Context; + const auto *Call = Result.Nodes.getStmtAs("call"); llvm::SmallPtrSet UsedArgs; for (unsigned I = 1, E = Call->getNumArgs(); I < E; ++I) { @@ -99,23 +84,13 @@ continue; // Emit a warning and fix-its that swap the arguments. - SourceRange LHSRange = LHS->getSourceRange(), - RHSRange = RHS->getSourceRange(); - auto D = - diag(Call->getLocStart(), "argument with implicit conversion from %0 " - "to %1 followed by argument converted from " - "%2 to %3, potentially swapped arguments.") + diag(Call->getLocStart(), "argument with implicit conversion from %0 " + "to %1 followed by argument converted from " + "%2 to %3, potentially swapped arguments.") << LHS->getType() << LHSFrom->getType() << RHS->getType() - << RHSFrom->getType() << LHSRange << RHSRange; - - StringRef RHSString = getAsString(Result, RHSRange); - StringRef LHSString = getAsString(Result, LHSRange); - if (!LHSString.empty() && !RHSString.empty()) { - D << FixItHint::CreateReplacement( - CharSourceRange::getTokenRange(LHSRange), RHSString) - << FixItHint::CreateReplacement( - CharSourceRange::getTokenRange(RHSRange), LHSString); - } + << RHSFrom->getType() + << utils::fixit::createReplacement(*LHS, *RHS, Ctx) + << utils::fixit::createReplacement(*RHS, *LHS, Ctx); // Remember that we emitted a warning for this argument. UsedArgs.insert(RHSCast); Index: clang-tidy/performance/ForRangeCopyCheck.cpp =================================================================== --- clang-tidy/performance/ForRangeCopyCheck.cpp +++ clang-tidy/performance/ForRangeCopyCheck.cpp @@ -66,9 +66,9 @@ diag(LoopVar.getLocation(), "the loop variable's type is not a reference type; this creates a " "copy in each iteration; consider making this a reference") - << utils::create_fix_it::changeVarDeclToReference(LoopVar, Context); + << utils::fixit::changeVarDeclToReference(LoopVar, Context); if (!LoopVar.getType().isConstQualified()) - Diagnostic << utils::create_fix_it::changeVarDeclToConst(LoopVar); + Diagnostic << utils::fixit::changeVarDeclToConst(LoopVar); return true; } @@ -84,8 +84,8 @@ diag(LoopVar.getLocation(), "loop variable is copied but only used as const reference; consider " "making it a const reference") - << utils::create_fix_it::changeVarDeclToConst(LoopVar) - << utils::create_fix_it::changeVarDeclToReference(LoopVar, Context); + << utils::fixit::changeVarDeclToConst(LoopVar) + << utils::fixit::changeVarDeclToReference(LoopVar, Context); return true; } Index: clang-tidy/performance/UnnecessaryCopyInitialization.cpp =================================================================== --- clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -24,9 +24,9 @@ if (Var.getLocation().isMacroID()) return; - Diagnostic << utils::create_fix_it::changeVarDeclToReference(Var, Context); + Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context); if (!Var.getType().isLocalConstQualified()) - Diagnostic << utils::create_fix_it::changeVarDeclToConst(Var); + Diagnostic << utils::fixit::changeVarDeclToConst(Var); } } // namespace Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp =================================================================== --- clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -79,10 +79,10 @@ for (const auto *FunctionDecl = Function; FunctionDecl != nullptr; FunctionDecl = FunctionDecl->getPreviousDecl()) { const auto &CurrentParam = *FunctionDecl->getParamDecl(Index); - Diag << utils::create_fix_it::changeVarDeclToReference(CurrentParam, - *Result.Context); + Diag << utils::fixit::changeVarDeclToReference(CurrentParam, + *Result.Context); if (!IsConstQualified) - Diag << utils::create_fix_it::changeVarDeclToConst(CurrentParam); + Diag << utils::fixit::changeVarDeclToConst(CurrentParam); } } Index: clang-tidy/readability/ElseAfterReturnCheck.cpp =================================================================== --- clang-tidy/readability/ElseAfterReturnCheck.cpp +++ clang-tidy/readability/ElseAfterReturnCheck.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "ElseAfterReturnCheck.h" +#include "../utils/FixItHintUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" @@ -28,20 +29,17 @@ this); } -static FixItHint removeToken(SourceLocation Loc) { - return FixItHint::CreateRemoval(CharSourceRange::getTokenRange(Loc, Loc)); -} - void ElseAfterReturnCheck::check(const MatchFinder::MatchResult &Result) { const auto *If = Result.Nodes.getNodeAs("if"); SourceLocation ElseLoc = If->getElseLoc(); DiagnosticBuilder Diag = diag(ElseLoc, "don't use else after return"); - Diag << removeToken(ElseLoc); + Diag << utils::fixit::createRemoval(ElseLoc); // FIXME: Removing the braces isn't always safe. Do a more careful analysis. // FIXME: Change clang-format to correctly un-indent the code. if (const auto *CS = Result.Nodes.getNodeAs("else")) - Diag << removeToken(CS->getLBracLoc()) << removeToken(CS->getRBracLoc()); + Diag << utils::fixit::createRemoval(CS->getLBracLoc()) + << utils::fixit::createRemoval(CS->getRBracLoc()); } } // namespace readability Index: clang-tidy/utils/FixItHintUtils.h =================================================================== --- clang-tidy/utils/FixItHintUtils.h +++ clang-tidy/utils/FixItHintUtils.h @@ -16,7 +16,35 @@ namespace clang { namespace tidy { namespace utils { -namespace create_fix_it { +namespace fixit { + +inline SourceRange getSourceRange(const SourceLocation &Loc) { + return SourceRange(Loc); +} + +inline SourceRange getSourceRange(const SourceRange &Range) { return Range; } + +template SourceRange getSourceRange(const T &Node) { + return Node.getSourceRange(); +} + +StringRef getText(SourceRange Range, const ASTContext &Context); + +template +StringRef getText(const T &Node, const ASTContext &Context) { + return getText(getSourceRange(Node), Context); +} + +template FixItHint createRemoval(const T &Node) { + return FixItHint::CreateRemoval(getSourceRange(Node)); +} + +template +FixItHint createReplacement(const D &Destination, const S &Source, + const ASTContext &Context) { + return FixItHint::CreateReplacement(getSourceRange(Destination), + getText(Source, Context)); +} /// \brief Creates fix to make VarDecl a reference by adding '&'. FixItHint changeVarDeclToReference(const VarDecl &Var, ASTContext &Context); @@ -24,8 +52,8 @@ /// \brief Creates fix to make VarDecl const qualified. FixItHint changeVarDeclToConst(const VarDecl &Var); -} // namespace create_fix_it -} // utils +} // namespace fixit +} // namespace utils } // namespace tidy } // namespace clang Index: clang-tidy/utils/FixItHintUtils.cpp =================================================================== --- clang-tidy/utils/FixItHintUtils.cpp +++ clang-tidy/utils/FixItHintUtils.cpp @@ -10,11 +10,18 @@ #include "FixItHintUtils.h" #include "LexerUtils.h" #include "clang/AST/ASTContext.h" +#include "clang/Lex/Lexer.h" namespace clang { namespace tidy { namespace utils { -namespace create_fix_it { +namespace fixit { + +StringRef getText(SourceRange Range, const ASTContext &Context) { + return Lexer::getSourceText(CharSourceRange::getTokenRange(Range), + Context.getSourceManager(), + Context.getLangOpts()); +} FixItHint changeVarDeclToReference(const VarDecl &Var, ASTContext &Context) { SourceLocation AmpLocation = Var.getLocation(); Index: test/clang-tidy/misc-swapped-arguments.cpp =================================================================== --- test/clang-tidy/misc-swapped-arguments.cpp +++ test/clang-tidy/misc-swapped-arguments.cpp @@ -23,7 +23,6 @@ F(b, M(Some, Function)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments. // In macro, don't emit fixits. -// CHECK-FIXES: F(b, M(Some, Function)); #define N F(b, SomeFunction())