clang-tools 24.0.0git
DeprecatedIosBaseAliasesCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "clang/ASTMatchers/ASTMatchFinder.h"
11#include <optional>
12
13using namespace clang::ast_matchers;
14
15namespace clang::tidy::modernize {
16
17static constexpr std::array<StringRef, 5> DeprecatedTypes = {
18 "::std::ios_base::io_state", "::std::ios_base::open_mode",
19 "::std::ios_base::seek_dir", "::std::ios_base::streamoff",
20 "::std::ios_base::streampos"};
21
22static std::optional<const char *> getReplacementType(StringRef Type) {
23 return llvm::StringSwitch<std::optional<const char *>>(Type)
24 .Case("io_state", "iostate")
25 .Case("open_mode", "openmode")
26 .Case("seek_dir", "seekdir")
27 .Default(std::nullopt);
28}
29
31 const auto IoStateDecl =
32 typedefDecl(hasAnyName(DeprecatedTypes)).bind("TypeDecl");
33 const auto IoStateType = typedefType(hasDeclaration(IoStateDecl));
34
35 Finder->addMatcher(typeLoc(loc(IoStateType)).bind("TypeLoc"), this);
36}
37
39 const MatchFinder::MatchResult &Result) {
40 const SourceManager &SM = *Result.SourceManager;
41
42 const auto *Typedef = Result.Nodes.getNodeAs<TypedefDecl>("TypeDecl");
43 const StringRef TypeName = Typedef->getName();
44 auto Replacement = getReplacementType(TypeName);
45
46 TypeLoc TL = *Result.Nodes.getNodeAs<TypeLoc>("TypeLoc");
47 if (const auto QTL = TL.getAs<QualifiedTypeLoc>())
48 TL = QTL.getUnqualifiedLoc();
49
50 SourceLocation IoStateLoc = TL.castAs<TypedefTypeLoc>().getNameLoc();
51 // Do not generate fixits for matches depending on template arguments and
52 // macro expansions.
53 bool Fix = Replacement && !TL.getType()->isDependentType();
54 if (IoStateLoc.isMacroID()) {
55 IoStateLoc = SM.getSpellingLoc(IoStateLoc);
56 Fix = false;
57 }
58
59 const SourceLocation EndLoc =
60 IoStateLoc.getLocWithOffset(TypeName.size() - 1);
61
62 if (Replacement) {
63 const char *FixName = *Replacement;
64 const auto Builder =
65 diag(IoStateLoc, "'std::ios_base::%0' is deprecated; use "
66 "'std::ios_base::%1' instead")
67 << TypeName << FixName;
68
69 if (Fix)
70 Builder << FixItHint::CreateReplacement(SourceRange(IoStateLoc, EndLoc),
71 FixName);
72 } else {
73 diag(IoStateLoc, "'std::ios_base::%0' is deprecated") << TypeName;
74 }
75}
76
77} // namespace clang::tidy::modernize
static cl::opt< bool > Fix("fix", desc(R"( Apply suggested fixes. Without -fix-errors clang-tidy will bail out if any compilation errors were found. )"), cl::init(false), cl::cat(ClangTidyCategory))
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
static std::optional< const char * > getReplacementType(StringRef Type)
static constexpr std::array< StringRef, 5 > DeprecatedTypes