1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* Based on LLVM/Clang.
*
* This file is distributed under the University of Illinois Open Source
* License. See LICENSE.TXT for details.
*
*/
#include <iostream>
#include <stack>
#include "plugin.hxx"
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendActions.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/Refactoring.h>
#include <llvm/Support/Signals.h>
/// Finds preprocessor usage which is redundant (only #ifndef for now).
namespace
{
struct Entry
{
clang::SourceLocation m_aLoc;
std::string m_aMacroName;
};
class RedundantPreprocessor : public clang::PPCallbacks, public loplugin::Plugin
{
public:
explicit RedundantPreprocessor(const loplugin::InstantiationData& data);
virtual void run() override;
void Ifndef(clang::SourceLocation aLoc, const clang::Token& rMacroNameTok,
const clang::MacroDefinition& rMacroDefinition) override;
void Ifdef(clang::SourceLocation aLoc, const clang::Token& rMacroNameTok,
const clang::MacroDefinition& rMacroDefinition) override;
void Endif(clang::SourceLocation aLoc, clang::SourceLocation aIfLoc) override;
enum
{
isPPCallback = true
};
private:
clang::Preprocessor& m_rPP;
std::vector<Entry> m_aDefStack;
std::vector<Entry> m_aNotDefStack;
};
RedundantPreprocessor::RedundantPreprocessor(const loplugin::InstantiationData& data)
: Plugin(data)
, m_rPP(compiler.getPreprocessor())
{
compiler.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(this));
}
void RedundantPreprocessor::run()
{
// nothing, only check preprocessor usage
}
void RedundantPreprocessor::Ifdef(clang::SourceLocation aLoc, const clang::Token& rMacroNameTok,
const clang::MacroDefinition& /*rMacroDefinition*/)
{
if (ignoreLocation(aLoc))
return;
std::string aMacroName = m_rPP.getSpelling(rMacroNameTok);
if (m_rPP.getSourceManager().isInMainFile(aLoc))
{
for (const auto& rEntry : m_aDefStack)
{
if (rEntry.m_aMacroName == aMacroName)
{
report(DiagnosticsEngine::Warning, "nested ifdef", aLoc);
report(DiagnosticsEngine::Note, "previous ifdef", rEntry.m_aLoc);
}
}
}
Entry aEntry;
aEntry.m_aLoc = aLoc;
aEntry.m_aMacroName = aMacroName;
m_aDefStack.push_back(aEntry);
}
void RedundantPreprocessor::Ifndef(clang::SourceLocation aLoc, const clang::Token& rMacroNameTok,
const clang::MacroDefinition& /*rMacroDefinition*/)
{
if (ignoreLocation(aLoc))
return;
std::string aMacroName = m_rPP.getSpelling(rMacroNameTok);
if (m_rPP.getSourceManager().isInMainFile(aLoc))
{
for (const auto& rEntry : m_aNotDefStack)
{
if (rEntry.m_aMacroName == aMacroName)
{
report(DiagnosticsEngine::Warning, "nested ifndef", aLoc);
report(DiagnosticsEngine::Note, "previous ifndef", rEntry.m_aLoc);
}
}
}
Entry aEntry;
aEntry.m_aLoc = aLoc;
aEntry.m_aMacroName = aMacroName;
m_aNotDefStack.push_back(aEntry);
}
void RedundantPreprocessor::Endif(clang::SourceLocation /*aLoc*/, clang::SourceLocation aIfLoc)
{
if (!m_aDefStack.empty())
{
if (aIfLoc == m_aDefStack.back().m_aLoc)
m_aDefStack.pop_back();
}
if (!m_aNotDefStack.empty())
{
if (aIfLoc == m_aNotDefStack.back().m_aLoc)
m_aNotDefStack.pop_back();
}
}
loplugin::Plugin::Registration<RedundantPreprocessor> X("redundantpreprocessor");
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|