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.startswith("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.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. 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.startswith("import"); 58 } 59 60 llvm::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 69 bool isSelfContainedHeader(const FileEntry *FE, const SourceManager &SM, 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 84 bool 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 96 std::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 120