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