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.
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>
23 /// Finds preprocessor usage which is redundant (only #ifndef for now).
29 clang::SourceLocation m_aLoc
;
30 std::string m_aMacroName
;
33 class RedundantPreprocessor
: public clang::PPCallbacks
, public Plugin
36 explicit RedundantPreprocessor(const InstantiationData
& data
);
37 virtual void run() override
;
38 void Ifndef(clang::SourceLocation aLoc
, const clang::Token
& rMacroNameTok
,
39 const clang::MacroDefinition
& rMacroDefinition
) override
;
40 void Ifdef(clang::SourceLocation aLoc
, const clang::Token
& rMacroNameTok
,
41 const clang::MacroDefinition
& rMacroDefinition
) override
;
42 void Endif(clang::SourceLocation aLoc
, clang::SourceLocation aIfLoc
) override
;
49 clang::Preprocessor
& m_rPP
;
50 std::vector
<Entry
> m_aDefStack
;
51 std::vector
<Entry
> m_aNotDefStack
;
54 RedundantPreprocessor::RedundantPreprocessor(const InstantiationData
& data
)
56 , m_rPP(compiler
.getPreprocessor())
58 compiler
.getPreprocessor().addPPCallbacks(std::unique_ptr
<PPCallbacks
>(this));
61 void RedundantPreprocessor::run()
63 // nothing, only check preprocessor usage
66 void RedundantPreprocessor::Ifdef(clang::SourceLocation aLoc
, const clang::Token
& rMacroNameTok
,
67 const clang::MacroDefinition
& /*rMacroDefinition*/)
69 if (ignoreLocation(aLoc
))
72 if (m_rPP
.getSourceManager().isInMainFile(aLoc
))
74 std::string aMacroName
= m_rPP
.getSpelling(rMacroNameTok
);
75 for (const auto& rEntry
: m_aDefStack
)
77 if (rEntry
.m_aMacroName
== aMacroName
)
79 report(DiagnosticsEngine::Warning
, "nested ifdef", aLoc
);
80 report(DiagnosticsEngine::Note
, "previous ifdef", rEntry
.m_aLoc
);
87 aEntry
.m_aMacroName
= m_rPP
.getSpelling(rMacroNameTok
);
88 m_aDefStack
.push_back(aEntry
);
91 void RedundantPreprocessor::Ifndef(clang::SourceLocation aLoc
, const clang::Token
& rMacroNameTok
,
92 const clang::MacroDefinition
& /*rMacroDefinition*/)
94 if (ignoreLocation(aLoc
))
97 if (m_rPP
.getSourceManager().isInMainFile(aLoc
))
99 std::string aMacroName
= m_rPP
.getSpelling(rMacroNameTok
);
100 for (const auto& rEntry
: m_aNotDefStack
)
102 if (rEntry
.m_aMacroName
== aMacroName
)
104 report(DiagnosticsEngine::Warning
, "nested ifndef", aLoc
);
105 report(DiagnosticsEngine::Note
, "previous ifndef", rEntry
.m_aLoc
);
111 aEntry
.m_aLoc
= aLoc
;
112 aEntry
.m_aMacroName
= m_rPP
.getSpelling(rMacroNameTok
);
113 m_aNotDefStack
.push_back(aEntry
);
116 void RedundantPreprocessor::Endif(clang::SourceLocation
/*aLoc*/, clang::SourceLocation aIfLoc
)
118 if (!m_aDefStack
.empty())
120 if (aIfLoc
== m_aDefStack
.back().m_aLoc
)
121 m_aDefStack
.pop_back();
123 if (!m_aNotDefStack
.empty())
125 if (aIfLoc
== m_aNotDefStack
.back().m_aLoc
)
126 m_aNotDefStack
.pop_back();
130 static Plugin::Registration
<RedundantPreprocessor
> X("redundantpreprocessor");
133 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */