clang-tools  14.0.0git
ReservedIdentifierCheck.cpp
Go to the documentation of this file.
1 //===--- ReservedIdentifierCheck.cpp - clang-tidy -------------------------===//
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 "../utils/Matchers.h"
11 #include "../utils/OptionsUtils.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 #include "clang/Lex/Token.h"
15 #include <algorithm>
16 #include <cctype>
17 
18 // FixItHint
19 
20 using namespace clang::ast_matchers;
21 
22 namespace clang {
23 namespace tidy {
24 namespace bugprone {
25 
26 static const char DoubleUnderscoreTag[] = "du";
27 static const char UnderscoreCapitalTag[] = "uc";
28 static const char GlobalUnderscoreTag[] = "global-under";
29 static const char NonReservedTag[] = "non-reserved";
30 
31 static const char Message[] =
32  "declaration uses identifier '%0', which is %select{a reserved "
33  "identifier|not a reserved identifier|reserved in the global namespace}1";
34 
35 static int getMessageSelectIndex(StringRef Tag) {
36  if (Tag == NonReservedTag)
37  return 1;
38  if (Tag == GlobalUnderscoreTag)
39  return 2;
40  return 0;
41 }
42 
43 ReservedIdentifierCheck::ReservedIdentifierCheck(StringRef Name,
44  ClangTidyContext *Context)
45  : RenamerClangTidyCheck(Name, Context),
46  Invert(Options.get("Invert", false)),
47  AllowedIdentifiers(utils::options::parseStringList(
48  Options.get("AllowedIdentifiers", ""))) {}
49 
52  Options.store(Opts, "Invert", Invert);
53  Options.store(Opts, "AllowedIdentifiers",
54  utils::options::serializeStringList(AllowedIdentifiers));
55 }
56 
57 static std::string collapseConsecutive(StringRef Str, char C) {
58  std::string Result;
59  std::unique_copy(Str.begin(), Str.end(), std::back_inserter(Result),
60  [C](char A, char B) { return A == C && B == C; });
61  return Result;
62 }
63 
64 static bool hasReservedDoubleUnderscore(StringRef Name,
65  const LangOptions &LangOpts) {
66  if (LangOpts.CPlusPlus)
67  return Name.find("__") != StringRef::npos;
68  return Name.startswith("__");
69 }
70 
71 static Optional<std::string>
72 getDoubleUnderscoreFixup(StringRef Name, const LangOptions &LangOpts) {
73  if (hasReservedDoubleUnderscore(Name, LangOpts))
74  return collapseConsecutive(Name, '_');
75  return None;
76 }
77 
78 static bool startsWithUnderscoreCapital(StringRef Name) {
79  return Name.size() >= 2 && Name[0] == '_' && std::isupper(Name[1]);
80 }
81 
82 static Optional<std::string> getUnderscoreCapitalFixup(StringRef Name) {
84  return std::string(Name.drop_front(1));
85  return None;
86 }
87 
89  bool IsInGlobalNamespace) {
90  return IsInGlobalNamespace && Name.size() >= 1 && Name[0] == '_';
91 }
92 
93 static Optional<std::string>
94 getUnderscoreGlobalNamespaceFixup(StringRef Name, bool IsInGlobalNamespace) {
95  if (startsWithUnderscoreInGlobalNamespace(Name, IsInGlobalNamespace))
96  return std::string(Name.drop_front(1));
97  return None;
98 }
99 
100 static std::string getNonReservedFixup(std::string Name) {
101  assert(!Name.empty());
102  if (Name[0] == '_' || std::isupper(Name[0]))
103  Name.insert(Name.begin(), '_');
104  else
105  Name.insert(Name.begin(), 2, '_');
106  return Name;
107 }
108 
109 static Optional<RenamerClangTidyCheck::FailureInfo>
110 getFailureInfoImpl(StringRef Name, bool IsInGlobalNamespace,
111  const LangOptions &LangOpts, bool Invert,
112  ArrayRef<std::string> AllowedIdentifiers) {
113  assert(!Name.empty());
114  if (llvm::is_contained(AllowedIdentifiers, Name))
115  return None;
116 
117  // TODO: Check for names identical to language keywords, and other names
118  // specifically reserved by language standards, e.g. C++ 'zombie names' and C
119  // future library directions
120 
121  using FailureInfo = RenamerClangTidyCheck::FailureInfo;
122  if (!Invert) {
123  Optional<FailureInfo> Info;
124  auto AppendFailure = [&](StringRef Kind, std::string &&Fixup) {
125  if (!Info) {
126  Info = FailureInfo{std::string(Kind), std::move(Fixup)};
127  } else {
128  Info->KindName += Kind;
129  Info->Fixup = std::move(Fixup);
130  }
131  };
132  auto InProgressFixup = [&] {
133  return Info
134  .map([](const FailureInfo &Info) { return StringRef(Info.Fixup); })
135  .getValueOr(Name);
136  };
137  if (auto Fixup = getDoubleUnderscoreFixup(InProgressFixup(), LangOpts))
138  AppendFailure(DoubleUnderscoreTag, std::move(*Fixup));
139  if (auto Fixup = getUnderscoreCapitalFixup(InProgressFixup()))
140  AppendFailure(UnderscoreCapitalTag, std::move(*Fixup));
141  if (auto Fixup = getUnderscoreGlobalNamespaceFixup(InProgressFixup(),
142  IsInGlobalNamespace))
143  AppendFailure(GlobalUnderscoreTag, std::move(*Fixup));
144 
145  return Info;
146  }
147  if (!(hasReservedDoubleUnderscore(Name, LangOpts) ||
149  startsWithUnderscoreInGlobalNamespace(Name, IsInGlobalNamespace)))
150  return FailureInfo{NonReservedTag, getNonReservedFixup(std::string(Name))};
151  return None;
152 }
153 
154 Optional<RenamerClangTidyCheck::FailureInfo>
155 ReservedIdentifierCheck::GetDeclFailureInfo(const NamedDecl *Decl,
156  const SourceManager &) const {
157  assert(Decl && Decl->getIdentifier() && !Decl->getName().empty() &&
158  !Decl->isImplicit() &&
159  "Decl must be an explicit identifier with a name.");
160  return getFailureInfoImpl(Decl->getName(),
161  isa<TranslationUnitDecl>(Decl->getDeclContext()),
162  getLangOpts(), Invert, AllowedIdentifiers);
163 }
164 
165 Optional<RenamerClangTidyCheck::FailureInfo>
166 ReservedIdentifierCheck::GetMacroFailureInfo(const Token &MacroNameTok,
167  const SourceManager &) const {
168  return getFailureInfoImpl(MacroNameTok.getIdentifierInfo()->getName(), true,
169  getLangOpts(), Invert, AllowedIdentifiers);
170 }
171 
172 RenamerClangTidyCheck::DiagInfo
173 ReservedIdentifierCheck::GetDiagInfo(const NamingCheckId &ID,
174  const NamingCheckFailure &Failure) const {
175  return DiagInfo{Message, [&](DiagnosticBuilder &Diag) {
176  Diag << ID.second
177  << getMessageSelectIndex(Failure.Info.KindName);
178  }};
179 }
180 
181 } // namespace bugprone
182 } // namespace tidy
183 } // namespace clang
clang::tidy::ClangTidyOptions::OptionMap
llvm::StringMap< ClangTidyValue > OptionMap
Definition: ClangTidyOptions.h:115
clang::tidy::bugprone::getNonReservedFixup
static std::string getNonReservedFixup(std::string Name)
Definition: ReservedIdentifierCheck.cpp:100
clang::tidy::RenamerClangTidyCheck::storeOptions
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Derived classes that override this function should call this method from the overridden method.
Definition: RenamerClangTidyCheck.cpp:108
clang::tidy::bugprone::Message
static const char Message[]
Definition: ReservedIdentifierCheck.cpp:31
Kind
BindArgumentKind Kind
Definition: AvoidBindCheck.cpp:59
clang::tidy::bugprone::startsWithUnderscoreCapital
static bool startsWithUnderscoreCapital(StringRef Name)
Definition: ReservedIdentifierCheck.cpp:78
clang::tidy::ClangTidyCheck::getLangOpts
const LangOptions & getLangOpts() const
Returns the language options from the context.
Definition: ClangTidyCheck.h:420
clang::tidy::bugprone::getFailureInfoImpl
static Optional< RenamerClangTidyCheck::FailureInfo > getFailureInfoImpl(StringRef Name, bool IsInGlobalNamespace, const LangOptions &LangOpts, bool Invert, ArrayRef< std::string > AllowedIdentifiers)
Definition: ReservedIdentifierCheck.cpp:110
clang::tidy::bugprone::DoubleUnderscoreTag
static const char DoubleUnderscoreTag[]
Definition: ReservedIdentifierCheck.cpp:26
clang::ast_matchers
Definition: AbseilMatcher.h:14
clang::tidy::bugprone::getUnderscoreGlobalNamespaceFixup
static Optional< std::string > getUnderscoreGlobalNamespaceFixup(StringRef Name, bool IsInGlobalNamespace)
Definition: ReservedIdentifierCheck.cpp:94
ns1::ns2::A
@ A
Definition: CategoricalFeature.h:3
clang::tidy::bugprone::getMessageSelectIndex
static int getMessageSelectIndex(StringRef Tag)
Definition: ReservedIdentifierCheck.cpp:35
clang::tidy::utils::options::serializeStringList
std::string serializeStringList(ArrayRef< std::string > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
Definition: OptionsUtils.cpp:30
clang::tidy::bugprone::startsWithUnderscoreInGlobalNamespace
static bool startsWithUnderscoreInGlobalNamespace(StringRef Name, bool IsInGlobalNamespace)
Definition: ReservedIdentifierCheck.cpp:88
Decl
const FunctionDecl * Decl
Definition: AvoidBindCheck.cpp:100
clang::tidy::utils::options::parseStringList
std::vector< std::string > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
Definition: OptionsUtils.cpp:18
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidyCheck.h:416
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:76
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
clang::tidy::bugprone::GlobalUnderscoreTag
static const char GlobalUnderscoreTag[]
Definition: ReservedIdentifierCheck.cpp:28
clang::tidy::bugprone::getDoubleUnderscoreFixup
static Optional< std::string > getDoubleUnderscoreFixup(StringRef Name, const LangOptions &LangOpts)
Definition: ReservedIdentifierCheck.cpp:72
clang::tidy::bugprone::getUnderscoreCapitalFixup
static Optional< std::string > getUnderscoreCapitalFixup(StringRef Name)
Definition: ReservedIdentifierCheck.cpp:82
clang::tidy::RenamerClangTidyCheck
Base class for clang-tidy checks that want to flag declarations and/or macros for renaming based on c...
Definition: RenamerClangTidyCheck.h:28
ReservedIdentifierCheck.h
clang::tidy::bugprone::collapseConsecutive
static std::string collapseConsecutive(StringRef Str, char C)
Definition: ReservedIdentifierCheck.cpp:57
Info
FunctionInfo Info
Definition: FunctionSizeCheck.cpp:120
ID
static char ID
Definition: Logger.cpp:74
C
const Criteria C
Definition: FunctionCognitiveComplexityCheck.cpp:93
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::tidy::bugprone::hasReservedDoubleUnderscore
static bool hasReservedDoubleUnderscore(StringRef Name, const LangOptions &LangOpts)
Definition: ReservedIdentifierCheck.cpp:64
clang::tidy::bugprone::UnderscoreCapitalTag
static const char UnderscoreCapitalTag[]
Definition: ReservedIdentifierCheck.cpp:27
clang::tidy::bugprone::ReservedIdentifierCheck::storeOptions
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
Definition: ReservedIdentifierCheck.cpp:50
clang::tidy::ClangTidyCheck::OptionsView::store
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
Definition: ClangTidyCheck.cpp:120
clang::tidy::RenamerClangTidyCheck::FailureInfo
Information describing a failed check.
Definition: RenamerClangTidyCheck.h:75
ns1::ns2::B
@ B
Definition: CategoricalFeature.h:3
Tag
HTMLTag Tag
Definition: HTMLGenerator.cpp:90
clang::tidy::bugprone::NonReservedTag
static const char NonReservedTag[]
Definition: ReservedIdentifierCheck.cpp:29