1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * Based on LLVM/Clang.
6 *
7 * This file is distributed under the University of Illinois Open Source
8 * License. See LICENSE.TXT for details.
9 *
10 */
11
12 #include <iostream>
13 #include <unordered_map>
14
15 #include "plugin.hxx"
16
17 #include <clang/Frontend/CompilerInstance.h>
18 #include <clang/Frontend/FrontendActions.h>
19 #include <clang/Tooling/CommonOptionsParser.h>
20 #include <clang/Tooling/Refactoring.h>
21 #include <llvm/Support/Signals.h>
22
23 /// Finds duplicated preprocessor defines, which generally indicate that some definition
24 /// needs to be centralised somewhere.
25
26 namespace loplugin
27 {
28 struct Entry
29 {
30 clang::SourceLocation m_aLoc;
31 };
32
33 class DuplicateDefines : public clang::PPCallbacks, public Plugin
34 {
35 public:
36 explicit DuplicateDefines(const InstantiationData& data);
37 virtual void run() override;
38 void MacroDefined(const Token& MacroNameTok, const MacroDirective* MD) override;
39 void MacroUndefined(const Token& MacroNameTok, const MacroDefinition& MD,
40 const MacroDirective* Undef) override;
41 enum
42 {
43 isPPCallback = true
44 };
45
46 private:
47 clang::Preprocessor& m_rPP;
48 std::unordered_map<std::string, Entry> m_aDefMap;
49 };
50
DuplicateDefines(const InstantiationData & data)51 DuplicateDefines::DuplicateDefines(const InstantiationData& data)
52 : Plugin(data)
53 , m_rPP(compiler.getPreprocessor())
54 {
55 compiler.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(this));
56 }
57
run()58 void DuplicateDefines::run()
59 {
60 // nothing, only check preprocessor usage
61 }
62
MacroDefined(const Token & rMacroNameTok,const MacroDirective *)63 void DuplicateDefines::MacroDefined(const Token& rMacroNameTok, const MacroDirective*)
64 {
65 auto aLoc = rMacroNameTok.getLocation();
66 if (ignoreLocation(aLoc))
67 return;
68
69 std::string aMacroName = m_rPP.getSpelling(rMacroNameTok);
70
71 // some testing macro
72 if (aMacroName == "RTL_STRING_CONST_FUNCTION")
73 return;
74 if (aMacroName == "rtl")
75 return;
76 // we replicate this macro in all the .hrc files
77 if (aMacroName == "NC_")
78 return;
79 // TODO no obvious fix for these
80 if (aMacroName == "FID_SEARCH_NOW" || aMacroName == "FID_SVX_START" || aMacroName == "FN_PARAM")
81 return;
82
83 if (!m_aDefMap.emplace(aMacroName, Entry{ aLoc }).second)
84 {
85 report(DiagnosticsEngine::Warning, "duplicate defines", aLoc);
86 report(DiagnosticsEngine::Note, "previous define", m_aDefMap[aMacroName].m_aLoc);
87 return;
88 }
89 }
90
MacroUndefined(const Token & rMacroNameTok,const MacroDefinition &,const MacroDirective *)91 void DuplicateDefines::MacroUndefined(const Token& rMacroNameTok, const MacroDefinition& /*MD*/,
92 const MacroDirective* /*Undef*/)
93 {
94 auto aLoc = rMacroNameTok.getLocation();
95 if (ignoreLocation(aLoc))
96 return;
97
98 std::string aMacroName = m_rPP.getSpelling(rMacroNameTok);
99 m_aDefMap.erase(aMacroName);
100 }
101
102 static Plugin::Registration<DuplicateDefines> X("duplicatedefines", false);
103 }
104
105 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
106