clang
22.0.0git
lib
Tooling
Inclusions
HeaderAnalysis.cpp
Go to the documentation of this file.
1
//===--- HeaderAnalysis.cpp -------------------------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "
clang/Tooling/Inclusions/HeaderAnalysis.h
"
10
#include "
clang/Basic/SourceLocation.h
"
11
#include "
clang/Lex/HeaderSearch.h
"
12
13
namespace
clang::tooling
{
14
namespace
{
15
16
// Is Line an #if or #ifdef directive?
17
// FIXME: This makes headers with #ifdef LINUX/WINDOWS/MACOS marked as non
18
// self-contained and is probably not what we want.
19
bool
isIf
(llvm::StringRef
Line
) {
20
Line
=
Line
.ltrim();
21
if
(!
Line
.consume_front(
"#"
))
22
return
false
;
23
Line
=
Line
.ltrim();
24
return
Line
.starts_with(
"if"
);
25
}
26
27
// Is Line an #error directive mentioning includes?
28
bool
isErrorAboutInclude(llvm::StringRef
Line
) {
29
Line
=
Line
.ltrim();
30
if
(!
Line
.consume_front(
"#"
))
31
return
false
;
32
Line
=
Line
.ltrim();
33
if
(!
Line
.starts_with(
"error"
))
34
return
false
;
35
return
Line
.contains_insensitive(
36
"includ"
);
// Matches "include" or "including".
37
}
38
39
// Heuristically headers that only want to be included via an umbrella.
40
bool
isDontIncludeMeHeader(StringRef Content) {
41
llvm::StringRef
Line
;
42
// Only sniff up to 100 lines or 10KB.
43
Content = Content.take_front(100 * 100);
44
for
(
unsigned
I = 0; I < 100 && !Content.empty(); ++I) {
45
std::tie(
Line
, Content) = Content.split(
'\n'
);
46
if
(
isIf
(
Line
) && isErrorAboutInclude(Content.split(
'\n'
).first))
47
return
true
;
48
}
49
return
false
;
50
}
51
52
bool
isImportLine(llvm::StringRef
Line
) {
53
Line
=
Line
.ltrim();
54
if
(!
Line
.consume_front(
"#"
))
55
return
false
;
56
Line
=
Line
.ltrim();
57
return
Line
.starts_with(
"import"
);
58
}
59
60
llvm::StringRef getFileContents(FileEntryRef FE,
const
SourceManager &
SM
) {
61
return
const_cast<
SourceManager &
>
(
SM
)
62
.getMemoryBufferForFileOrNone(FE)
63
.value_or(llvm::MemoryBufferRef())
64
.getBuffer();
65
}
66
67
}
// namespace
68
69
bool
isSelfContainedHeader
(
FileEntryRef
FE,
const
SourceManager
&
SM
,
70
const
HeaderSearch
&HeaderInfo) {
71
if
(!HeaderInfo.
isFileMultipleIncludeGuarded
(FE) &&
72
!HeaderInfo.
hasFileBeenImported
(FE) &&
73
// Any header that contains #imports is supposed to be #import'd so no
74
// need to check for anything but the main-file.
75
(
SM
.getFileEntryForID(
SM
.getMainFileID()) != FE ||
76
!
codeContainsImports
(getFileContents(FE,
SM
))))
77
return
false
;
78
// This pattern indicates that a header can't be used without
79
// particular preprocessor state, usually set up by another header.
80
return
!isDontIncludeMeHeader(getFileContents(FE,
SM
));
81
}
82
83
bool
codeContainsImports
(llvm::StringRef Code) {
84
// Only sniff up to 100 lines or 10KB.
85
Code = Code.take_front(100 * 100);
86
llvm::StringRef
Line
;
87
for
(
unsigned
I = 0; I < 100 && !Code.empty(); ++I) {
88
std::tie(
Line
, Code) = Code.split(
'\n'
);
89
if
(isImportLine(
Line
))
90
return
true
;
91
}
92
return
false
;
93
}
94
95
std::optional<StringRef>
parseIWYUPragma
(
const
char
*
Text
) {
96
// Skip the comment start, // or /*.
97
if
(
Text
[0] !=
'/'
|| (
Text
[1] !=
'/'
&&
Text
[1] !=
'*'
))
98
return
std::nullopt;
99
bool
BlockComment =
Text
[1] ==
'*'
;
100
Text
+= 2;
101
102
// Per spec, direcitves are whitespace- and case-sensitive.
103
constexpr
llvm::StringLiteral IWYUPragma =
" IWYU pragma: "
;
104
if
(strncmp(
Text
, IWYUPragma.data(), IWYUPragma.size()))
105
return
std::nullopt;
106
Text
+= IWYUPragma.size();
107
const
char
*End =
Text
;
108
while
(*End != 0 && *End !=
'\n'
)
109
++End;
110
StringRef Rest(
Text
, End -
Text
);
111
// Strip off whitespace and comment markers to avoid confusion. This isn't
112
// fully-compatible with IWYU, which splits into whitespace-delimited tokens.
113
if
(BlockComment)
114
Rest.consume_back(
"*/"
);
115
return
Rest.trim();
116
}
117
118
}
// namespace clang::tooling
isIf
bool isIf(bool AllowConstexprMacro=true) const
Definition
FormatToken.h:1176
HeaderAnalysis.h
HeaderSearch.h
SM
#define SM(sm)
Definition
OffloadArch.cpp:16
SourceLocation.h
Defines the clang::SourceLocation class and associated facilities.
clang::FileEntryRef
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
Definition
FileEntry.h:57
clang::HeaderSearch
Encapsulates the information needed to find the file referenced by a #include or #include_next,...
Definition
HeaderSearch.h:237
clang::HeaderSearch::hasFileBeenImported
bool hasFileBeenImported(FileEntryRef File) const
Determine whether the given file is known to have ever been #imported.
Definition
HeaderSearch.h:587
clang::HeaderSearch::isFileMultipleIncludeGuarded
bool isFileMultipleIncludeGuarded(FileEntryRef File) const
Determine whether this file is intended to be safe from multiple inclusions, e.g.,...
Definition
HeaderSearch.cpp:1370
clang::SourceManager
This class handles loading and caching of source files into memory.
Definition
SourceManager.h:663
clang::tooling
Definition
AllTUsExecution.h:22
clang::tooling::codeContainsImports
bool codeContainsImports(llvm::StringRef Code)
This scans the given source code to see if it contains import(s).
Definition
HeaderAnalysis.cpp:83
clang::tooling::isSelfContainedHeader
bool isSelfContainedHeader(FileEntryRef FE, const SourceManager &SM, const HeaderSearch &HeaderInfo)
Returns true if the given physical file is a self-contained header.
Definition
HeaderAnalysis.cpp:69
clang::tooling::parseIWYUPragma
std::optional< llvm::StringRef > parseIWYUPragma(const char *Text)
If Text begins an Include-What-You-Use directive, returns it.
Definition
HeaderAnalysis.cpp:95
clang::PragmaClangSectionKind::Text
@ Text
Definition
Sema.h:469
clang::SourceLocIdentKind::Line
@ Line
Definition
Expr.h:4943
Generated on
for clang by
1.14.0