summaryrefslogtreecommitdiffstats
path: root/compilerplugins/clang/includeform.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'compilerplugins/clang/includeform.cxx')
-rw-r--r--compilerplugins/clang/includeform.cxx119
1 files changed, 119 insertions, 0 deletions
diff --git a/compilerplugins/clang/includeform.cxx b/compilerplugins/clang/includeform.cxx
new file mode 100644
index 0000000000..da955c20d3
--- /dev/null
+++ b/compilerplugins/clang/includeform.cxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <memory>
+
+#include "config_clang.h"
+
+#include "plugin.hxx"
+
+// Enforces the "Rules for #include directives (C/C++)" described in README.md.
+
+namespace {
+
+class IncludeForm final: public PPCallbacks, public loplugin::RewritePlugin {
+public:
+ explicit IncludeForm(loplugin::InstantiationData const & data):
+ RewritePlugin(data)
+ { compiler.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(this)); }
+
+private:
+ void run() override {}
+
+ void InclusionDirective(
+ SourceLocation HashLoc, Token const & IncludeTok, StringRef,
+ bool IsAngled, CharSourceRange FilenameRange,
+#if CLANG_VERSION >= 160000
+ OptionalFileEntryRef File,
+#elif CLANG_VERSION >= 150000
+ Optional<FileEntryRef> File,
+#else
+ FileEntry const * File,
+#endif
+ StringRef SearchPath, StringRef, clang::Module const *, SrcMgr::CharacteristicKind) override
+ {
+ if (ignoreLocation(HashLoc)) {
+ return;
+ }
+ if (!File) { // in case of "fatal error: '...' file not found"
+ return;
+ }
+ if (IncludeTok.getIdentifierInfo()->getPPKeywordID() != tok::pp_include)
+ {
+ return;
+ }
+ auto const uno = isInUnoIncludeFile(HashLoc)
+ && !compiler.getSourceManager().isInMainFile(HashLoc);
+ // exclude the various compat.cxx that are included in
+ // isInUnoIncludeFile
+ //TODO: 'uno' should be false if HashLoc is inside an
+ // '#ifdef LIBO_INTERNAL_ONLY' block
+ bool shouldUseAngles;
+ if (uno) {
+ shouldUseAngles
+ = (!(loplugin::hasPathnamePrefix(SearchPath, SRCDIR "/")
+ || loplugin::hasPathnamePrefix(SearchPath, BUILDDIR "/"))
+ || loplugin::hasPathnamePrefix(
+ SearchPath, WORKDIR "/UnpackedTarball/"));
+ } else {
+ auto dir1 = std::string(SearchPath);
+ loplugin::normalizeDotDotInFilePath(dir1);
+ auto const file = StringRef(
+ compiler.getSourceManager().getPresumedLoc(HashLoc)
+ .getFilename());
+ auto pos = file.rfind('/');
+#if defined _WIN32
+ auto const pos2 = file.rfind('\\');
+ if (pos2 != StringRef::npos
+ && (pos == StringRef::npos || pos2 > pos))
+ {
+ pos = pos2;
+ }
+#endif
+ auto dir2 = std::string(file.take_front(pos));
+ loplugin::normalizeDotDotInFilePath(dir2);
+ shouldUseAngles = !loplugin::isSamePathname(dir1, dir2);
+ }
+ if (shouldUseAngles == IsAngled) {
+ return;
+ }
+ if (rewriter != nullptr) {
+ auto last = FilenameRange.getEnd().getLocWithOffset(-1);
+ if ((compiler.getSourceManager().getCharacterData(
+ FilenameRange.getBegin())[0]
+ == (IsAngled ? '<' : '"'))
+ && (compiler.getSourceManager().getCharacterData(last)[0]
+ == (IsAngled ? '>' : '"'))
+ && replaceText(
+ FilenameRange.getBegin(), 1, shouldUseAngles ? "<" : "\"")
+ && replaceText(last, 1, shouldUseAngles ? ">" : "\""))
+ {
+ //TODO: atomically only replace both or neither
+ return;
+ }
+ }
+ report(
+ DiagnosticsEngine::Warning,
+ ("%select{|in UNO API include file, }0replace"
+ " %select{\"...\"|<...>}1 include form with"
+ " %select{\"...\"|<...>}2 for inclusion of %select{%select{a"
+ " source file next to the current source file|a source file not"
+ " next to the current source file, or a header}2|%select{a source"
+ " file|a header}2}0, %3"),
+ FilenameRange.getBegin())
+ << uno << IsAngled << shouldUseAngles << File->getName()
+ << FilenameRange;
+ }
+};
+
+static loplugin::Plugin::Registration<IncludeForm> reg("includeform", true);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */