Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp
35266 views
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
119
120