1 //===--- RedundantPreprocessorCheck.cpp - clang-tidy ----------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "RedundantPreprocessorCheck.h"
10 #include "clang/Frontend/CompilerInstance.h"
11 #include "clang/Lex/Lexer.h"
12 #include "clang/Lex/PPCallbacks.h"
13 #include "clang/Lex/Preprocessor.h"
15 namespace clang::tidy::readability
{
18 /// Information about an opening preprocessor directive.
19 struct PreprocessorEntry
{
21 /// Condition used after the preprocessor directive.
22 std::string Condition
;
25 const char WarningDescription
[] =
26 "nested redundant %select{#if|#ifdef|#ifndef}0; consider removing it";
27 const char NoteDescription
[] = "previous %select{#if|#ifdef|#ifndef}0 was here";
29 class RedundantPreprocessorCallbacks
: public PPCallbacks
{
30 enum DirectiveKind
{ DK_If
= 0, DK_Ifdef
= 1, DK_Ifndef
= 2 };
33 explicit RedundantPreprocessorCallbacks(ClangTidyCheck
&Check
,
35 : Check(Check
), PP(PP
) {}
37 void If(SourceLocation Loc
, SourceRange ConditionRange
,
38 ConditionValueKind ConditionValue
) override
{
40 Lexer::getSourceText(CharSourceRange::getTokenRange(ConditionRange
),
41 PP
.getSourceManager(), PP
.getLangOpts());
42 checkMacroRedundancy(Loc
, Condition
, IfStack
, DK_If
, DK_If
, true);
45 void Ifdef(SourceLocation Loc
, const Token
&MacroNameTok
,
46 const MacroDefinition
&MacroDefinition
) override
{
47 std::string MacroName
= PP
.getSpelling(MacroNameTok
);
48 checkMacroRedundancy(Loc
, MacroName
, IfdefStack
, DK_Ifdef
, DK_Ifdef
, true);
49 checkMacroRedundancy(Loc
, MacroName
, IfndefStack
, DK_Ifdef
, DK_Ifndef
,
53 void Ifndef(SourceLocation Loc
, const Token
&MacroNameTok
,
54 const MacroDefinition
&MacroDefinition
) override
{
55 std::string MacroName
= PP
.getSpelling(MacroNameTok
);
56 checkMacroRedundancy(Loc
, MacroName
, IfndefStack
, DK_Ifndef
, DK_Ifndef
,
58 checkMacroRedundancy(Loc
, MacroName
, IfdefStack
, DK_Ifndef
, DK_Ifdef
,
62 void Endif(SourceLocation Loc
, SourceLocation IfLoc
) override
{
63 if (!IfStack
.empty() && IfLoc
== IfStack
.back().Loc
)
65 if (!IfdefStack
.empty() && IfLoc
== IfdefStack
.back().Loc
)
66 IfdefStack
.pop_back();
67 if (!IfndefStack
.empty() && IfLoc
== IfndefStack
.back().Loc
)
68 IfndefStack
.pop_back();
72 void checkMacroRedundancy(SourceLocation Loc
, StringRef MacroName
,
73 SmallVector
<PreprocessorEntry
, 4> &Stack
,
74 DirectiveKind WarningKind
, DirectiveKind NoteKind
,
76 if (PP
.getSourceManager().isInMainFile(Loc
)) {
77 for (const auto &Entry
: Stack
) {
78 if (Entry
.Condition
== MacroName
) {
79 Check
.diag(Loc
, WarningDescription
) << WarningKind
;
80 Check
.diag(Entry
.Loc
, NoteDescription
, DiagnosticIDs::Note
)
87 // This is an actual directive to be remembered.
88 Stack
.push_back({Loc
, std::string(MacroName
)});
91 ClangTidyCheck
&Check
;
93 SmallVector
<PreprocessorEntry
, 4> IfStack
;
94 SmallVector
<PreprocessorEntry
, 4> IfdefStack
;
95 SmallVector
<PreprocessorEntry
, 4> IfndefStack
;
99 void RedundantPreprocessorCheck::registerPPCallbacks(
100 const SourceManager
&SM
, Preprocessor
*PP
, Preprocessor
*ModuleExpanderPP
) {
102 ::std::make_unique
<RedundantPreprocessorCallbacks
>(*this, *PP
));
105 } // namespace clang::tidy::readability