1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
7 * This file is distributed under the University of Illinois Open Source
8 * License. See LICENSE.TXT for details.
14 #include <unordered_map>
18 #include <clang/Frontend/CompilerInstance.h>
19 #include <clang/Frontend/FrontendActions.h>
20 #include <clang/Tooling/CommonOptionsParser.h>
21 #include <clang/Tooling/Refactoring.h>
22 #include <llvm/Support/Signals.h>
24 /// Finds duplicated preprocessor defines, which generally indicate that some definition
25 /// needs to be centralised somewhere.
31 clang::SourceLocation m_aLoc
;
34 class DuplicateDefines
: public clang::PPCallbacks
, public loplugin::Plugin
37 explicit DuplicateDefines(const loplugin::InstantiationData
& data
);
38 virtual void run() override
;
39 void MacroDefined(const Token
& MacroNameTok
, const MacroDirective
* MD
) override
;
40 void MacroUndefined(const Token
& MacroNameTok
, const MacroDefinition
& MD
,
41 const MacroDirective
* Undef
) override
;
48 clang::Preprocessor
& m_rPP
;
49 std::unordered_map
<std::string
, Entry
> m_aDefMap
;
52 DuplicateDefines::DuplicateDefines(const loplugin::InstantiationData
& data
)
54 , m_rPP(compiler
.getPreprocessor())
56 compiler
.getPreprocessor().addPPCallbacks(std::unique_ptr
<PPCallbacks
>(this));
59 void DuplicateDefines::run()
61 // nothing, only check preprocessor usage
64 void DuplicateDefines::MacroDefined(const Token
& rMacroNameTok
, const MacroDirective
*)
66 auto aLoc
= rMacroNameTok
.getLocation();
67 if (ignoreLocation(aLoc
))
70 std::string aMacroName
= m_rPP
.getSpelling(rMacroNameTok
);
73 if (aMacroName
== "RTL_STRING_CONST_FUNCTION")
75 if (aMacroName
== "rtl")
77 // we replicate these macros in all the .hrc files
78 if (aMacroName
== "NC_" || aMacroName
== "NNC_")
80 // We define this prior to including <windows.h>:
81 if (aMacroName
== "WIN32_LEAN_AND_MEAN")
85 // TODO no obvious fix for these
86 if (aMacroName
== "FID_SEARCH_NOW" || aMacroName
== "FID_SVX_START" || aMacroName
== "FN_PARAM")
88 // ignore for now, requires adding too many includes to sw/
89 if (aMacroName
== "MM50")
92 // ignore for now, we have the same define in svx and sw, but I can't remove one of them because
93 // they reference strings in different resource bundles
94 if (aMacroName
== "STR_UNDO_COL_DELETE" || aMacroName
== "STR_UNDO_ROW_DELETE"
95 || aMacroName
== "STR_TABLE_NUMFORMAT" || aMacroName
== "STR_DELETE")
98 if (m_aDefMap
.emplace(aMacroName
, Entry
{ aLoc
}).second
)
103 // Happens e.g. with macros defined in include/premac.h, which is intended to be included
104 // (without include guards) multiple times:
105 auto const other
= m_aDefMap
[aMacroName
].m_aLoc
;
106 assert(aLoc
== compiler
.getSourceManager().getSpellingLoc(aLoc
));
107 assert(other
== compiler
.getSourceManager().getSpellingLoc(other
));
108 if ((compiler
.getSourceManager().getFilename(aLoc
)
109 == compiler
.getSourceManager().getFilename(other
))
110 && (compiler
.getSourceManager().getSpellingLineNumber(aLoc
)
111 == compiler
.getSourceManager().getSpellingLineNumber(other
))
112 && (compiler
.getSourceManager().getSpellingColumnNumber(aLoc
)
113 == compiler
.getSourceManager().getSpellingColumnNumber(other
)))
118 report(DiagnosticsEngine::Warning
, "duplicate defines", aLoc
);
119 report(DiagnosticsEngine::Note
, "previous define", other
);
122 void DuplicateDefines::MacroUndefined(const Token
& rMacroNameTok
, const MacroDefinition
& /*MD*/,
123 const MacroDirective
* /*Undef*/)
125 auto aLoc
= rMacroNameTok
.getLocation();
126 if (ignoreLocation(aLoc
))
129 std::string aMacroName
= m_rPP
.getSpelling(rMacroNameTok
);
130 m_aDefMap
.erase(aMacroName
);
133 loplugin::Plugin::Registration
<DuplicateDefines
> X("duplicatedefines", true);
136 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */