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 *, SrcMgr::CharacteristicKind
) override
41 if (ignoreLocation(HashLoc
)) {
44 if (!File
) { // in case of "fatal error: '...' file not found"
47 if (IncludeTok
.getIdentifierInfo()->getPPKeywordID() != tok::pp_include
)
51 auto const uno
= isInUnoIncludeFile(HashLoc
)
52 && !compiler
.getSourceManager().isInMainFile(HashLoc
);
53 // exclude the various compat.cxx that are included in
55 //TODO: 'uno' should be false if HashLoc is inside an
56 // '#ifdef LIBO_INTERNAL_ONLY' block
60 = (!(loplugin::hasPathnamePrefix(SearchPath
, SRCDIR
"/")
61 || loplugin::hasPathnamePrefix(SearchPath
, BUILDDIR
"/"))
62 || loplugin::hasPathnamePrefix(
63 SearchPath
, WORKDIR
"/UnpackedTarball/"));
65 auto dir1
= std::string(SearchPath
);
66 loplugin::normalizeDotDotInFilePath(dir1
);
67 auto const file
= StringRef(
68 compiler
.getSourceManager().getPresumedLoc(HashLoc
)
70 auto pos
= file
.rfind('/');
72 auto const pos2
= file
.rfind('\\');
73 if (pos2
!= StringRef::npos
74 && (pos
== StringRef::npos
|| pos2
> pos
))
79 auto dir2
= std::string(file
.take_front(pos
));
80 loplugin::normalizeDotDotInFilePath(dir2
);
81 shouldUseAngles
= !loplugin::isSamePathname(dir1
, dir2
);
83 if (shouldUseAngles
== IsAngled
) {
86 if (rewriter
!= nullptr) {
87 auto last
= FilenameRange
.getEnd().getLocWithOffset(-1);
88 if ((compiler
.getSourceManager().getCharacterData(
89 FilenameRange
.getBegin())[0]
90 == (IsAngled
? '<' : '"'))
91 && (compiler
.getSourceManager().getCharacterData(last
)[0]
92 == (IsAngled
? '>' : '"'))
94 FilenameRange
.getBegin(), 1, shouldUseAngles
? "<" : "\"")
95 && replaceText(last
, 1, shouldUseAngles
? ">" : "\""))
97 //TODO: atomically only replace both or neither
102 DiagnosticsEngine::Warning
,
103 ("%select{|in UNO API include file, }0replace"
104 " %select{\"...\"|<...>}1 include form with"
105 " %select{\"...\"|<...>}2 for inclusion of %select{%select{a"
106 " source file next to the current source file|a source file not"
107 " next to the current source file, or a header}2|%select{a source"
108 " file|a header}2}0, %3"),
109 FilenameRange
.getBegin())
110 << uno
<< IsAngled
<< shouldUseAngles
<< File
->getName()
115 static loplugin::Plugin::Registration
<IncludeForm
> reg("includeform", true);
119 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */