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 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" 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 const char WarningDescription[] = 28 "nested redundant %select{#if|#ifdef|#ifndef}0; consider removing it"; 29 const char NoteDescription[] = "previous %select{#if|#ifdef|#ifndef}0 was here"; 30 31 class RedundantPreprocessorCallbacks : public PPCallbacks { 32 enum DirectiveKind { DK_If = 0, DK_Ifdef = 1, DK_Ifndef = 2 }; 33 34 public: 35 explicit RedundantPreprocessorCallbacks(ClangTidyCheck &Check, 36 Preprocessor &PP) 37 : Check(Check), PP(PP) {} 38 39 void If(SourceLocation Loc, SourceRange ConditionRange, 40 ConditionValueKind ConditionValue) override { 41 StringRef Condition = 42 Lexer::getSourceText(CharSourceRange::getTokenRange(ConditionRange), 43 PP.getSourceManager(), PP.getLangOpts()); 44 checkMacroRedundancy(Loc, Condition, IfStack, DK_If, DK_If, true); 45 } 46 47 void Ifdef(SourceLocation Loc, const Token &MacroNameTok, 48 const MacroDefinition &MacroDefinition) override { 49 std::string MacroName = PP.getSpelling(MacroNameTok); 50 checkMacroRedundancy(Loc, MacroName, IfdefStack, DK_Ifdef, DK_Ifdef, true); 51 checkMacroRedundancy(Loc, MacroName, IfndefStack, DK_Ifdef, DK_Ifndef, 52 false); 53 } 54 55 void Ifndef(SourceLocation Loc, const Token &MacroNameTok, 56 const MacroDefinition &MacroDefinition) override { 57 std::string MacroName = PP.getSpelling(MacroNameTok); 58 checkMacroRedundancy(Loc, MacroName, IfndefStack, DK_Ifndef, DK_Ifndef, 59 true); 60 checkMacroRedundancy(Loc, MacroName, IfdefStack, DK_Ifndef, DK_Ifdef, 61 false); 62 } 63 64 void Endif(SourceLocation Loc, SourceLocation IfLoc) override { 65 if (!IfStack.empty() && IfLoc == IfStack.back().Loc) 66 IfStack.pop_back(); 67 if (!IfdefStack.empty() && IfLoc == IfdefStack.back().Loc) 68 IfdefStack.pop_back(); 69 if (!IfndefStack.empty() && IfLoc == IfndefStack.back().Loc) 70 IfndefStack.pop_back(); 71 } 72 73 private: 74 void checkMacroRedundancy(SourceLocation Loc, StringRef MacroName, 75 SmallVector<PreprocessorEntry, 4> &Stack, 76 DirectiveKind WarningKind, DirectiveKind NoteKind, 77 bool Store) { 78 if (PP.getSourceManager().isInMainFile(Loc)) { 79 for (const auto &Entry : Stack) { 80 if (Entry.Condition == MacroName) { 81 Check.diag(Loc, WarningDescription) << WarningKind; 82 Check.diag(Entry.Loc, NoteDescription, DiagnosticIDs::Note) 83 << NoteKind; 84 } 85 } 86 } 87 88 if (Store) 89 // This is an actual directive to be remembered. 90 Stack.push_back({Loc, std::string(MacroName)}); 91 } 92 93 ClangTidyCheck &Check; 94 Preprocessor &PP; 95 SmallVector<PreprocessorEntry, 4> IfStack; 96 SmallVector<PreprocessorEntry, 4> IfdefStack; 97 SmallVector<PreprocessorEntry, 4> IfndefStack; 98 }; 99 } // namespace 100 101 void RedundantPreprocessorCheck::registerPPCallbacks( 102 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { 103 PP->addPPCallbacks( 104 ::std::make_unique<RedundantPreprocessorCallbacks>(*this, *PP)); 105 } 106 107 } // namespace readability 108 } // namespace tidy 109 } // namespace clang 110