clang-tools  11.0.0git
RedundantPreprocessorCheck.cpp
Go to the documentation of this file.
1 //===--- RedundantPreprocessorCheck.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 "clang/Frontend/CompilerInstance.h"
11 #include "clang/Lex/Lexer.h"
12 #include "clang/Lex/PPCallbacks.h"
13 #include "clang/Lex/Preprocessor.h"
14 
15 namespace clang {
16 namespace tidy {
17 namespace readability {
18 
19 namespace {
20 /// Information about an opening preprocessor directive.
21 struct PreprocessorEntry {
22  SourceLocation Loc;
23  /// Condition used after the preprocessor directive.
24  std::string Condition;
25 };
26 
27 class RedundantPreprocessorCallbacks : public PPCallbacks {
28  enum DirectiveKind { DK_If = 0, DK_Ifdef = 1, DK_Ifndef = 2 };
29 
30 public:
31  explicit RedundantPreprocessorCallbacks(ClangTidyCheck &Check,
32  Preprocessor &PP)
33  : Check(Check), PP(PP),
34  WarningDescription("nested redundant %select{#if|#ifdef|#ifndef}0; "
35  "consider removing it"),
36  NoteDescription("previous %select{#if|#ifdef|#ifndef}0 was here") {}
37 
38  void If(SourceLocation Loc, SourceRange ConditionRange,
39  ConditionValueKind ConditionValue) override {
40  StringRef Condition =
41  Lexer::getSourceText(CharSourceRange::getTokenRange(ConditionRange),
42  PP.getSourceManager(), PP.getLangOpts());
43  CheckMacroRedundancy(Loc, Condition, IfStack, DK_If, DK_If, true);
44  }
45 
46  void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
47  const MacroDefinition &MacroDefinition) override {
48  std::string MacroName = PP.getSpelling(MacroNameTok);
49  CheckMacroRedundancy(Loc, MacroName, IfdefStack, DK_Ifdef, DK_Ifdef, true);
50  CheckMacroRedundancy(Loc, MacroName, IfndefStack, DK_Ifdef, DK_Ifndef,
51  false);
52  }
53 
54  void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
55  const MacroDefinition &MacroDefinition) override {
56  std::string MacroName = PP.getSpelling(MacroNameTok);
57  CheckMacroRedundancy(Loc, MacroName, IfndefStack, DK_Ifndef, DK_Ifndef,
58  true);
59  CheckMacroRedundancy(Loc, MacroName, IfdefStack, DK_Ifndef, DK_Ifdef,
60  false);
61  }
62 
63  void Endif(SourceLocation Loc, SourceLocation IfLoc) override {
64  if (!IfStack.empty() && IfLoc == IfStack.back().Loc)
65  IfStack.pop_back();
66  if (!IfdefStack.empty() && IfLoc == IfdefStack.back().Loc)
67  IfdefStack.pop_back();
68  if (!IfndefStack.empty() && IfLoc == IfndefStack.back().Loc)
69  IfndefStack.pop_back();
70  }
71 
72 private:
73  void CheckMacroRedundancy(SourceLocation Loc, StringRef MacroName,
74  SmallVector<PreprocessorEntry, 4> &Stack,
75  DirectiveKind WarningKind, DirectiveKind NoteKind,
76  bool Store) {
77  if (PP.getSourceManager().isInMainFile(Loc)) {
78  for (const auto &Entry : Stack) {
79  if (Entry.Condition == MacroName) {
80  Check.diag(Loc, WarningDescription) << WarningKind;
81  Check.diag(Entry.Loc, NoteDescription, DiagnosticIDs::Note)
82  << NoteKind;
83  }
84  }
85  }
86 
87  if (Store)
88  // This is an actual directive to be remembered.
89  Stack.push_back({Loc, std::string(MacroName)});
90  }
91 
92  ClangTidyCheck &Check;
93  Preprocessor &PP;
94  SmallVector<PreprocessorEntry, 4> IfStack;
95  SmallVector<PreprocessorEntry, 4> IfdefStack;
96  SmallVector<PreprocessorEntry, 4> IfndefStack;
97  const std::string WarningDescription;
98  const std::string NoteDescription;
99 };
100 } // namespace
101 
103  const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
104  PP->addPPCallbacks(
105  ::std::make_unique<RedundantPreprocessorCallbacks>(*this, *PP));
106 }
107 
108 } // namespace readability
109 } // namespace tidy
110 } // namespace clang
SourceLocation Loc
clang::tok::PPKeywordKind DirectiveKind
Location Loc
Definition: Modularize.cpp:438
clang::PPCallbacks::ConditionValueKind ConditionValue
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
Override this to register PPCallbacks in the preprocessor.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::string Condition
Condition used after the preprocessor directive.