clang 17.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.startswith("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.startswith("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.startswith("import");
58}
59
60llvm::StringRef getFileContents(const FileEntry *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 HeaderSearch &HeaderInfo) {
71 assert(FE);
72 if (!HeaderInfo.isFileMultipleIncludeGuarded(FE) &&
73 !HeaderInfo.hasFileBeenImported(FE) &&
74 // Any header that contains #imports is supposed to be #import'd so no
75 // need to check for anything but the main-file.
76 (SM.getFileEntryForID(SM.getMainFileID()) != FE ||
77 !codeContainsImports(getFileContents(FE, SM))))
78 return false;
79 // This pattern indicates that a header can't be used without
80 // particular preprocessor state, usually set up by another header.
81 return !isDontIncludeMeHeader(getFileContents(FE, SM));
82}
83
84bool codeContainsImports(llvm::StringRef Code) {
85 // Only sniff up to 100 lines or 10KB.
86 Code = Code.take_front(100 * 100);
87 llvm::StringRef Line;
88 for (unsigned I = 0; I < 100 && !Code.empty(); ++I) {
89 std::tie(Line, Code) = Code.split('\n');
90 if (isImportLine(Line))
91 return true;
92 }
93 return false;
94}
95
96std::optional<StringRef> parseIWYUPragma(const char *Text) {
97 // Skip the comment start, // or /*.
98 if (Text[0] != '/' || (Text[1] != '/' && Text[1] != '*'))
99 return std::nullopt;
100 bool BlockComment = Text[1] == '*';
101 Text += 2;
102
103 // Per spec, direcitves are whitespace- and case-sensitive.
104 constexpr llvm::StringLiteral IWYUPragma = " IWYU pragma: ";
105 if (strncmp(Text, IWYUPragma.data(), IWYUPragma.size()))
106 return std::nullopt;
107 Text += IWYUPragma.size();
108 const char *End = Text;
109 while (*End != 0 && *End != '\n')
110 ++End;
111 StringRef Rest(Text, End - Text);
112 // Strip off whitespace and comment markers to avoid confusion. This isn't
113 // fully-compatible with IWYU, which splits into whitespace-delimited tokens.
114 if (BlockComment)
115 Rest.consume_back("*/");
116 return Rest.trim();
117}
118
119} // namespace clang::tooling
#define SM(sm)
Definition: Cuda.cpp:80
StringRef Text
Definition: Format.cpp:2796
Defines the clang::SourceLocation class and associated facilities.
Cached information about one file (either on disk or in the virtual file system).
Definition: FileEntry.h:353
Encapsulates the information needed to find the file referenced by a #include or #include_next,...
Definition: HeaderSearch.h:223
bool isFileMultipleIncludeGuarded(const FileEntry *File)
Determine whether this file is intended to be safe from multiple inclusions, e.g.,...
bool hasFileBeenImported(const FileEntry *File)
Determine whether the given file is known to have ever been #imported.
Definition: HeaderSearch.h:559
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).
std::optional< llvm::StringRef > parseIWYUPragma(const char *Text)
If Text begins an Include-What-You-Use directive, returns it.
bool isSelfContainedHeader(const FileEntry *FE, const SourceManager &SM, HeaderSearch &HeaderInfo)
Returns true if the given physical file is a self-contained header.