clang  19.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 
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 
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
#define SM(sm)
Definition: Cuda.cpp:83
StringRef Text
Definition: Format.cpp:2977
Defines the clang::SourceLocation class and associated facilities.
SourceLocation End
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:253
bool hasFileBeenImported(FileEntryRef File) const
Determine whether the given file is known to have ever been #imported.
Definition: HeaderSearch.h:594
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.