1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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/.
12 #include "config_clang.h"
16 // Enforces the "Rules for #include directives (C/C++)" described in README.md.
20 class IncludeForm final
: public PPCallbacks
, public loplugin::RewritePlugin
{
22 explicit IncludeForm(loplugin::InstantiationData
const & data
):
24 { compiler
.getPreprocessor().addPPCallbacks(std::unique_ptr
<PPCallbacks
>(this)); }
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
,
37 FileEntry
const * File
,
39 StringRef SearchPath
, StringRef
, clang::Module
const *,
40 #if CLANG_VERSION >= 190000
43 SrcMgr::CharacteristicKind
) override
45 if (ignoreLocation(HashLoc
)) {
48 if (!File
) { // in case of "fatal error: '...' file not found"
51 if (IncludeTok
.getIdentifierInfo()->getPPKeywordID() != tok::pp_include
)
55 auto const uno
= isInUnoIncludeFile(HashLoc
)
56 && !compiler
.getSourceManager().isInMainFile(HashLoc
);
57 // exclude the various compat.cxx that are included in
59 //TODO: 'uno' should be false if HashLoc is inside an
60 // '#ifdef LIBO_INTERNAL_ONLY' block
64 = (!(loplugin::hasPathnamePrefix(SearchPath
, SRCDIR
"/")
65 || loplugin::hasPathnamePrefix(SearchPath
, BUILDDIR
"/"))
66 || loplugin::hasPathnamePrefix(
67 SearchPath
, WORKDIR
"/UnpackedTarball/"));
69 auto dir1
= std::string(SearchPath
);
70 loplugin::normalizeDotDotInFilePath(dir1
);
71 auto const file
= StringRef(
72 compiler
.getSourceManager().getPresumedLoc(HashLoc
)
74 auto pos
= file
.rfind('/');
76 auto const pos2
= file
.rfind('\\');
77 if (pos2
!= StringRef::npos
78 && (pos
== StringRef::npos
|| pos2
> pos
))
83 auto dir2
= std::string(file
.take_front(pos
));
84 loplugin::normalizeDotDotInFilePath(dir2
);
85 shouldUseAngles
= !loplugin::isSamePathname(dir1
, dir2
);
87 if (shouldUseAngles
== IsAngled
) {
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
? '>' : '"'))
98 FilenameRange
.getBegin(), 1, shouldUseAngles
? "<" : "\"")
99 && replaceText(last
, 1, shouldUseAngles
? ">" : "\""))
101 //TODO: atomically only replace both or neither
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()
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: */