clang 20.0.0git
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
12
13namespace clang::tooling {
14namespace {
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.
19bool 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?
28bool 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.
40bool 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
52bool 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
60llvm::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
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
83bool 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
95std::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
#define SM(sm)
Definition: Cuda.cpp:84
StringRef Text
Definition: Format.cpp:3033
Defines the clang::SourceLocation class and associated facilities.
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
Definition: FileEntry.h:57
Encapsulates the information needed to find the file referenced by a #include or #include_next,...
Definition: HeaderSearch.h:237
bool hasFileBeenImported(FileEntryRef File) const
Determine whether the given file is known to have ever been #imported.
Definition: HeaderSearch.h:578
bool isFileMultipleIncludeGuarded(FileEntryRef File) const
Determine whether this file is intended to be safe from multiple inclusions, e.g.,...
This class handles loading and caching of source files into memory.
bool codeContainsImports(llvm::StringRef Code)
This scans the given source code to see if it contains #import(s).
bool isSelfContainedHeader(FileEntryRef FE, const SourceManager &SM, const HeaderSearch &HeaderInfo)
Returns true if the given physical file is a self-contained header.
std::optional< llvm::StringRef > parseIWYUPragma(const char *Text)
If Text begins an Include-What-You-Use directive, returns it.