tdf#161878 Ignore nested SYMBOL field inside IF field
[LibreOffice.git] / compilerplugins / clang / includeform.cxx
blob173f9e28841bb4d932ef05a4c7ed89ad51826176
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <memory>
12 #include "config_clang.h"
14 #include "plugin.hxx"
16 // Enforces the "Rules for #include directives (C/C++)" described in README.md.
18 namespace {
20 class IncludeForm final: public PPCallbacks, public loplugin::RewritePlugin {
21 public:
22 explicit IncludeForm(loplugin::InstantiationData const & data):
23 RewritePlugin(data)
24 { compiler.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(this)); }
26 private:
27 void run() override {}
29 void InclusionDirective(
30 SourceLocation HashLoc, Token const & IncludeTok, StringRef,
31 bool IsAngled, CharSourceRange FilenameRange,
32 #if CLANG_VERSION >= 160000
33 OptionalFileEntryRef File,
34 #elif CLANG_VERSION >= 150000
35 Optional<FileEntryRef> File,
36 #else
37 FileEntry const * File,
38 #endif
39 StringRef SearchPath, StringRef, clang::Module const *,
40 #if CLANG_VERSION >= 190000
41 bool,
42 #endif
43 SrcMgr::CharacteristicKind) override
45 if (ignoreLocation(HashLoc)) {
46 return;
48 if (!File) { // in case of "fatal error: '...' file not found"
49 return;
51 if (IncludeTok.getIdentifierInfo()->getPPKeywordID() != tok::pp_include)
53 return;
55 auto const uno = isInUnoIncludeFile(HashLoc)
56 && !compiler.getSourceManager().isInMainFile(HashLoc);
57 // exclude the various compat.cxx that are included in
58 // isInUnoIncludeFile
59 //TODO: 'uno' should be false if HashLoc is inside an
60 // '#ifdef LIBO_INTERNAL_ONLY' block
61 bool shouldUseAngles;
62 if (uno) {
63 shouldUseAngles
64 = (!(loplugin::hasPathnamePrefix(SearchPath, SRCDIR "/")
65 || loplugin::hasPathnamePrefix(SearchPath, BUILDDIR "/"))
66 || loplugin::hasPathnamePrefix(
67 SearchPath, WORKDIR "/UnpackedTarball/"));
68 } else {
69 auto dir1 = std::string(SearchPath);
70 loplugin::normalizeDotDotInFilePath(dir1);
71 auto const file = StringRef(
72 compiler.getSourceManager().getPresumedLoc(HashLoc)
73 .getFilename());
74 auto pos = file.rfind('/');
75 #if defined _WIN32
76 auto const pos2 = file.rfind('\\');
77 if (pos2 != StringRef::npos
78 && (pos == StringRef::npos || pos2 > pos))
80 pos = pos2;
82 #endif
83 auto dir2 = std::string(file.take_front(pos));
84 loplugin::normalizeDotDotInFilePath(dir2);
85 shouldUseAngles = !loplugin::isSamePathname(dir1, dir2);
87 if (shouldUseAngles == IsAngled) {
88 return;
90 if (rewriter != nullptr) {
91 auto last = FilenameRange.getEnd().getLocWithOffset(-1);
92 if ((compiler.getSourceManager().getCharacterData(
93 FilenameRange.getBegin())[0]
94 == (IsAngled ? '<' : '"'))
95 && (compiler.getSourceManager().getCharacterData(last)[0]
96 == (IsAngled ? '>' : '"'))
97 && replaceText(
98 FilenameRange.getBegin(), 1, shouldUseAngles ? "<" : "\"")
99 && replaceText(last, 1, shouldUseAngles ? ">" : "\""))
101 //TODO: atomically only replace both or neither
102 return;
105 report(
106 DiagnosticsEngine::Warning,
107 ("%select{|in UNO API include file, }0replace"
108 " %select{\"...\"|<...>}1 include form with"
109 " %select{\"...\"|<...>}2 for inclusion of %select{%select{a"
110 " source file next to the current source file|a source file not"
111 " next to the current source file, or a header}2|%select{a source"
112 " file|a header}2}0, %3"),
113 FilenameRange.getBegin())
114 << uno << IsAngled << shouldUseAngles << File->getName()
115 << FilenameRange;
119 static loplugin::Plugin::Registration<IncludeForm> reg("includeform", true);
123 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */