Path: blob/main/contrib/llvm-project/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp
35266 views
//===--- HeaderAnalysis.cpp -------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/Tooling/Inclusions/HeaderAnalysis.h"9#include "clang/Basic/SourceLocation.h"10#include "clang/Lex/HeaderSearch.h"1112namespace clang::tooling {13namespace {1415// Is Line an #if or #ifdef directive?16// FIXME: This makes headers with #ifdef LINUX/WINDOWS/MACOS marked as non17// self-contained and is probably not what we want.18bool isIf(llvm::StringRef Line) {19Line = Line.ltrim();20if (!Line.consume_front("#"))21return false;22Line = Line.ltrim();23return Line.starts_with("if");24}2526// Is Line an #error directive mentioning includes?27bool isErrorAboutInclude(llvm::StringRef Line) {28Line = Line.ltrim();29if (!Line.consume_front("#"))30return false;31Line = Line.ltrim();32if (!Line.starts_with("error"))33return false;34return Line.contains_insensitive(35"includ"); // Matches "include" or "including".36}3738// Heuristically headers that only want to be included via an umbrella.39bool isDontIncludeMeHeader(StringRef Content) {40llvm::StringRef Line;41// Only sniff up to 100 lines or 10KB.42Content = Content.take_front(100 * 100);43for (unsigned I = 0; I < 100 && !Content.empty(); ++I) {44std::tie(Line, Content) = Content.split('\n');45if (isIf(Line) && isErrorAboutInclude(Content.split('\n').first))46return true;47}48return false;49}5051bool isImportLine(llvm::StringRef Line) {52Line = Line.ltrim();53if (!Line.consume_front("#"))54return false;55Line = Line.ltrim();56return Line.starts_with("import");57}5859llvm::StringRef getFileContents(FileEntryRef FE, const SourceManager &SM) {60return const_cast<SourceManager &>(SM)61.getMemoryBufferForFileOrNone(FE)62.value_or(llvm::MemoryBufferRef())63.getBuffer();64}6566} // namespace6768bool isSelfContainedHeader(FileEntryRef FE, const SourceManager &SM,69const HeaderSearch &HeaderInfo) {70if (!HeaderInfo.isFileMultipleIncludeGuarded(FE) &&71!HeaderInfo.hasFileBeenImported(FE) &&72// Any header that contains #imports is supposed to be #import'd so no73// need to check for anything but the main-file.74(SM.getFileEntryForID(SM.getMainFileID()) != FE ||75!codeContainsImports(getFileContents(FE, SM))))76return false;77// This pattern indicates that a header can't be used without78// particular preprocessor state, usually set up by another header.79return !isDontIncludeMeHeader(getFileContents(FE, SM));80}8182bool codeContainsImports(llvm::StringRef Code) {83// Only sniff up to 100 lines or 10KB.84Code = Code.take_front(100 * 100);85llvm::StringRef Line;86for (unsigned I = 0; I < 100 && !Code.empty(); ++I) {87std::tie(Line, Code) = Code.split('\n');88if (isImportLine(Line))89return true;90}91return false;92}9394std::optional<StringRef> parseIWYUPragma(const char *Text) {95// Skip the comment start, // or /*.96if (Text[0] != '/' || (Text[1] != '/' && Text[1] != '*'))97return std::nullopt;98bool BlockComment = Text[1] == '*';99Text += 2;100101// Per spec, direcitves are whitespace- and case-sensitive.102constexpr llvm::StringLiteral IWYUPragma = " IWYU pragma: ";103if (strncmp(Text, IWYUPragma.data(), IWYUPragma.size()))104return std::nullopt;105Text += IWYUPragma.size();106const char *End = Text;107while (*End != 0 && *End != '\n')108++End;109StringRef Rest(Text, End - Text);110// Strip off whitespace and comment markers to avoid confusion. This isn't111// fully-compatible with IWYU, which splits into whitespace-delimited tokens.112if (BlockComment)113Rest.consume_back("*/");114return Rest.trim();115}116117} // namespace clang::tooling118119120