12#include "clang/Basic/SourceLocation.h"
13#include "clang/Basic/SourceManager.h"
14#include "clang/Frontend/CompilerInstance.h"
15#include "clang/Lex/HeaderSearch.h"
16#include "clang/Lex/PPCallbacks.h"
17#include "clang/Lex/Preprocessor.h"
18#include "clang/Tooling/Inclusions/HeaderAnalysis.h"
19#include "llvm/ADT/SmallVector.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/Support/Path.h"
31 : SM(
CI.getSourceManager()),
39 OptionalFileEntryRef
File,
42 const clang::Module * ,
43 SrcMgr::CharacteristicKind FileKind)
override {
44 auto MainFID = SM.getMainFileID();
57 std::string(
File ?
File->getFileEntry().tryGetRealPathName() :
"");
58 Inc.HashOffset = SM.getFileOffset(HashLoc);
60 SM.getLineNumber(SM.getFileID(HashLoc), Inc.HashOffset) - 1;
61 Inc.FileKind = FileKind;
62 Inc.Directive = IncludeTok.getIdentifierInfo()->getPPKeywordID();
65 Inc.HeaderID =
static_cast<unsigned>(HID);
67 if (
auto StdlibHeader = tooling::stdlib::Header::named(Inc.Written)) {
70 if (!llvm::is_contained(IDs, HID))
74 Out->MainFileIncludesBySpelling.try_emplace(Inc.Written)
80 auto IncludingFileEntry = SM.getFileEntryRefForID(SM.getFileID(HashLoc));
81 if (!IncludingFileEntry) {
82 assert(SM.getBufferName(HashLoc).startswith(
"<") &&
83 "Expected #include location to be a file or <built-in>");
85 IncludingFileEntry = SM.getFileEntryRefForID(MainFID);
94 SrcMgr::CharacteristicKind FileType,
95 FileID PrevFID)
override {
97 case PPCallbacks::EnterFile:
99 if (BuiltinFile.isInvalid() && SM.isWrittenInBuiltinFile(
Loc)) {
100 BuiltinFile = SM.getFileID(
Loc);
101 InBuiltinFile =
true;
104 case PPCallbacks::ExitFile: {
106 if (PrevFID == BuiltinFile)
107 InBuiltinFile =
false;
110 case PPCallbacks::RenameFile:
111 case PPCallbacks::SystemHeaderPragma:
119 bool inMainFile()
const {
return Level == 1; }
121 const SourceManager &SM;
125 bool InBuiltinFile =
false;
131 return Include.startswith(
"<") || Include.startswith(
"\"");
140 llvm::StringRef HintPath) {
145 return U.takeError();
149 return IncludePath.takeError();
150 if (!IncludePath->empty())
151 return HeaderFile{std::move(*IncludePath),
true};
155 return Resolved.takeError();
156 return HeaderFile{std::move(*Resolved),
false};
168 llvm::SmallVector<SymbolInclude, 1> Headers;
169 for (
const auto &Include : Includes)
170 Headers.push_back({Include.IncludeHeader, Include.supportedDirectives()});
175 auto &SM =
CI.getSourceManager();
176 MainFileEntry = SM.getFileEntryForID(SM.getMainFileID());
177 auto Collector = std::make_unique<RecordHeaders>(
CI,
this);
178 CI.getPreprocessor().addPPCallbacks(std::move(Collector));
181std::optional<IncludeStructure::HeaderID>
184 if (
Entry == MainFileEntry) {
187 auto It = UIDToIndex.find(
Entry->getUniqueID());
188 if (It == UIDToIndex.end())
195 if (&
Entry.getFileEntry() == MainFileEntry) {
196 if (RealPathNames.front().empty())
197 RealPathNames.front() = MainFileEntry->tryGetRealPathName().str();
200 auto R = UIDToIndex.try_emplace(
204 RealPathNames.emplace_back();
206 std::string &RealPathName = RealPathNames[
static_cast<unsigned>(Result)];
207 if (RealPathName.empty())
208 RealPathName =
Entry.getFileEntry().tryGetRealPathName().str();
212llvm::DenseMap<IncludeStructure::HeaderID, unsigned>
215 llvm::DenseMap<HeaderID, unsigned> Result;
216 assert(
static_cast<unsigned>(
Root) < RealPathNames.size());
218 std::vector<IncludeStructure::HeaderID> CurrentLevel;
219 CurrentLevel.push_back(
Root);
220 llvm::DenseSet<IncludeStructure::HeaderID> Seen;
224 std::vector<IncludeStructure::HeaderID> PreviousLevel;
225 for (
unsigned Level = 1; !CurrentLevel.empty(); ++Level) {
226 PreviousLevel.clear();
227 PreviousLevel.swap(CurrentLevel);
228 for (
const auto &
Parent : PreviousLevel) {
230 if (Seen.insert(Child).second) {
231 CurrentLevel.push_back(Child);
232 Result[Child] = Level;
240llvm::SmallVector<const Inclusion *>
242 llvm::SmallVector<const Inclusion *> Includes;
243 for (
auto Idx : MainFileIncludesBySpelling.lookup(Spelling))
249 IncludedHeaders.insert(Inc.
Written);
251 IncludedHeaders.insert(Inc.
Resolved);
258 assert(InsertedHeader.
valid());
259 if (!HeaderSearchInfo && !InsertedHeader.
Verbatim)
261 if (FileName == DeclaringHeader || FileName == InsertedHeader.
File)
263 auto Included = [&](llvm::StringRef Header) {
264 return IncludedHeaders.contains(Header);
266 return !Included(DeclaringHeader) && !Included(InsertedHeader.
File);
269std::optional<std::string>
271 llvm::StringRef IncludingFile)
const {
272 assert(InsertedHeader.
valid());
274 return InsertedHeader.
File;
275 bool IsSystem =
false;
276 std::string Suggested;
277 if (HeaderSearchInfo) {
278 Suggested = HeaderSearchInfo->suggestPathToFileForDiagnostics(
279 InsertedHeader.
File, BuildDir, IncludingFile, &IsSystem);
282 StringRef IncludingDir = llvm::sys::path::parent_path(IncludingFile);
283 SmallString<256> RelFile(InsertedHeader.
File);
285 llvm::sys::path::replace_path_prefix(RelFile, IncludingDir,
"./");
286 Suggested = llvm::sys::path::convert_to_slash(
287 llvm::sys::path::remove_leading_dotslash(RelFile));
290 if (llvm::sys::path::is_absolute(Suggested))
293 Suggested =
"<" + Suggested +
">";
295 Suggested =
"\"" + Suggested +
"\"";
299std::optional<TextEdit>
301 tooling::IncludeDirective
Directive)
const {
302 std::optional<TextEdit>
Edit;
304 Inserter.insert(VerbatimHeader.trim(
"\"<>"),
305 VerbatimHeader.startswith(
"<"),
Directive))
CompiledFragmentImpl & Out
bool IsAngled
true if this was an include with angle brackets
const MacroDirective * Directive
std::unique_ptr< CompilerInvocation > CI
llvm::raw_string_ostream OS
void addExisting(const Inclusion &Inc)
std::optional< std::string > calculateIncludePath(const HeaderFile &InsertedHeader, llvm::StringRef IncludingFile) const
Determines the preferred way to #include a file, taking into account the search path.
bool shouldInsertInclude(PathRef DeclaringHeader, const HeaderFile &InsertedHeader) const
Checks whether to add an #include of the header into File.
std::optional< TextEdit > insert(llvm::StringRef VerbatimHeader, tooling::IncludeDirective Directive) const
Calculates an edit that inserts VerbatimHeader into code.
llvm::SmallVector< const Inclusion * > mainFileIncludesWithSpelling(llvm::StringRef Spelling) const
static const HeaderID MainFileID
llvm::DenseMap< HeaderID, unsigned > includeDepth(HeaderID Root=MainFileID) const
std::vector< Inclusion > MainFileIncludes
llvm::DenseMap< tooling::stdlib::Header, llvm::SmallVector< HeaderID > > StdlibHeaders
HeaderID getOrCreateID(FileEntryRef Entry)
void collect(const CompilerInstance &CI)
std::optional< HeaderID > getID(const FileEntry *Entry) const
llvm::DenseMap< HeaderID, SmallVector< HeaderID > > IncludeChildren
static llvm::Expected< std::string > includeSpelling(const URI &U)
Gets the preferred spelling of this file for #include, if there is one, e.g.
static llvm::Expected< std::string > resolve(const URI &U, llvm::StringRef HintPath="")
Resolves the absolute path of U.
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
bool isLiteralInclude(llvm::StringRef Include)
Returns true if Include is literal include like "path" or <path>.
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
bool operator==(const Inclusion &LHS, const Inclusion &RHS)
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
SourceLocation translatePreamblePatchLocation(SourceLocation Loc, const SourceManager &SM)
Translates locations inside preamble patch to their main-file equivalent using presumed locations.
llvm::Expected< HeaderFile > toHeaderFile(llvm::StringRef Header, llvm::StringRef HintPath)
Creates a HeaderFile from Header which can be either a URI or a literal include.
llvm::SmallVector< SymbolInclude, 1 > getRankedIncludes(const Symbol &Sym)
llvm::StringRef PathRef
A typedef to represent a ref to file path.
TextEdit replacementToEdit(llvm::StringRef Code, const tooling::Replacement &R)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
A set of edits generated for a single file.
tok::PPKeywordKind Directive
SrcMgr::CharacteristicKind FileKind
The class presents a C++ symbol, e.g.
llvm::SmallVector< IncludeHeaderWithReferences, 1 > IncludeHeaders
One Symbol can potentially be included via different headers.