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
, FileEntry
const * File
,
32 StringRef SearchPath
, StringRef
, clang::Module
const *
33 #if CLANG_VERSION >= 70000
34 , SrcMgr::CharacteristicKind
38 if (ignoreLocation(HashLoc
)) {
41 if (File
== nullptr) { // in case of "fatal error: '...' file not found"
44 if (IncludeTok
.getIdentifierInfo()->getPPKeywordID() != tok::pp_include
)
48 auto const uno
= isInUnoIncludeFile(HashLoc
)
49 && !compiler
.getSourceManager().isInMainFile(HashLoc
);
50 // exclude the various compat.cxx that are included in
52 //TODO: 'uno' should be false if HashLoc is inside an
53 // '#ifdef LIBO_INTERNAL_ONLY' block
57 = (!(loplugin::hasPathnamePrefix(SearchPath
, SRCDIR
"/")
58 || loplugin::hasPathnamePrefix(SearchPath
, BUILDDIR
"/"))
59 || loplugin::hasPathnamePrefix(
60 SearchPath
, WORKDIR
"/UnpackedTarball/"));
62 auto dir1
= std::string(SearchPath
);
63 loplugin::normalizeDotDotInFilePath(dir1
);
64 auto const file
= StringRef(
65 compiler
.getSourceManager().getPresumedLoc(HashLoc
)
67 auto pos
= file
.rfind('/');
69 auto const pos2
= file
.rfind('\\');
70 if (pos2
!= StringRef::npos
71 && (pos
== StringRef::npos
|| pos2
> pos
))
76 auto dir2
= std::string(file
.take_front(pos
));
77 loplugin::normalizeDotDotInFilePath(dir2
);
78 shouldUseAngles
= !loplugin::isSamePathname(dir1
, dir2
);
80 if (shouldUseAngles
== IsAngled
) {
83 if (rewriter
!= nullptr) {
84 auto last
= FilenameRange
.getEnd().getLocWithOffset(-1);
85 if ((compiler
.getSourceManager().getCharacterData(
86 FilenameRange
.getBegin())[0]
87 == (IsAngled
? '<' : '"'))
88 && (compiler
.getSourceManager().getCharacterData(last
)[0]
89 == (IsAngled
? '>' : '"'))
91 FilenameRange
.getBegin(), 1, shouldUseAngles
? "<" : "\"")
92 && replaceText(last
, 1, shouldUseAngles
? ">" : "\""))
94 //TODO: atomically only replace both or neither
99 DiagnosticsEngine::Warning
,
100 ("%select{|in UNO API include file, }0replace"
101 " %select{\"...\"|<...>}1 include form with"
102 " %select{\"...\"|<...>}2 for inclusion of %select{%select{a"
103 " source file next to the current source file|a source file not"
104 " next to the current source file, or a header}2|%select{a source"
105 " file|a header}2}0, %3"),
106 FilenameRange
.getBegin())
107 << uno
<< IsAngled
<< shouldUseAngles
<< File
->getName()
112 static loplugin::Plugin::Registration
<IncludeForm
> reg("includeform", true);
116 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */