1 //===--- HeaderAnalysis.cpp -------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "clang/Tooling/Inclusions/HeaderAnalysis.h"
10 #include "clang/Basic/SourceLocation.h"
11 #include "clang/Lex/HeaderSearch.h"
13 namespace clang::tooling
{
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
) {
21 if (!Line
.consume_front("#"))
24 return Line
.startswith("if");
27 // Is Line an #error directive mentioning includes?
28 bool isErrorAboutInclude(llvm::StringRef Line
) {
30 if (!Line
.consume_front("#"))
33 if (!Line
.startswith("error"))
35 return Line
.contains_insensitive(
36 "includ"); // Matches "include" or "including".
39 // Heuristically headers that only want to be included via an umbrella.
40 bool isDontIncludeMeHeader(StringRef Content
) {
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
))
52 bool isImportLine(llvm::StringRef Line
) {
54 if (!Line
.consume_front("#"))
57 return Line
.startswith("import");
60 llvm::StringRef
getFileContents(FileEntryRef FE
, const SourceManager
&SM
) {
61 return const_cast<SourceManager
&>(SM
)
62 .getMemoryBufferForFileOrNone(FE
)
63 .value_or(llvm::MemoryBufferRef())
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
))))
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
));
83 bool codeContainsImports(llvm::StringRef Code
) {
84 // Only sniff up to 100 lines or 10KB.
85 Code
= Code
.take_front(100 * 100);
87 for (unsigned I
= 0; I
< 100 && !Code
.empty(); ++I
) {
88 std::tie(Line
, Code
) = Code
.split('\n');
89 if (isImportLine(Line
))
95 std::optional
<StringRef
> parseIWYUPragma(const char *Text
) {
96 // Skip the comment start, // or /*.
97 if (Text
[0] != '/' || (Text
[1] != '/' && Text
[1] != '*'))
99 bool BlockComment
= Text
[1] == '*';
102 // Per spec, direcitves are whitespace- and case-sensitive.
103 constexpr llvm::StringLiteral IWYUPragma
= " IWYU pragma: ";
104 if (strncmp(Text
, IWYUPragma
.data(), IWYUPragma
.size()))
106 Text
+= IWYUPragma
.size();
107 const char *End
= Text
;
108 while (*End
!= 0 && *End
!= '\n')
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.
114 Rest
.consume_back("*/");
118 } // namespace clang::tooling