14 #include "clang/Frontend/CompilerInstance.h" 15 #include "clang/Frontend/CompilerInvocation.h" 16 #include "clang/Frontend/FrontendActions.h" 17 #include "clang/Lex/HeaderSearch.h" 18 #include "llvm/Support/Path.h" 26 RecordHeaders(
const SourceManager &SM, IncludeStructure *Out)
31 void InclusionDirective(SourceLocation HashLoc,
const Token & ,
33 CharSourceRange FilenameRange,
const FileEntry *
File,
37 SrcMgr::CharacteristicKind FileKind)
override {
38 if (SM.isWrittenInMainFile(HashLoc)) {
39 Out->MainFileIncludes.emplace_back();
40 auto &Inc = Out->MainFileIncludes.back();
43 (IsAngled ?
"<" + FileName +
">" :
"\"" + FileName +
"\"").str();
44 Inc.Resolved = File ? File->tryGetRealPathName() :
"";
45 Inc.HashOffset = SM.getFileOffset(HashLoc);
46 Inc.FileKind = FileKind;
49 auto *IncludingFileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc));
50 if (!IncludingFileEntry) {
51 assert(SM.getBufferName(HashLoc).startswith(
"<") &&
52 "Expected #include location to be a file or <built-in>");
54 IncludingFileEntry = SM.getFileEntryForID(SM.getMainFileID());
56 Out->recordInclude(IncludingFileEntry->getName(), File->getName(),
57 File->tryGetRealPathName());
62 const SourceManager &SM;
63 IncludeStructure *Out;
69 return Include.startswith(
"<") || Include.startswith(
"\"");
74 (!Verbatim && llvm::sys::path::is_absolute(File));
77 std::unique_ptr<PPCallbacks>
80 return llvm::make_unique<RecordHeaders>(SM, Out);
84 llvm::StringRef IncludedName,
85 llvm::StringRef IncludedRealName) {
86 auto Child = fileIndex(IncludedName);
87 if (!IncludedRealName.empty() && RealPathNames[Child].empty())
88 RealPathNames[Child] = IncludedRealName;
89 auto Parent = fileIndex(IncludingName);
90 IncludeChildren[Parent].push_back(Child);
93 unsigned IncludeStructure::fileIndex(llvm::StringRef
Name) {
94 auto R = NameToIndex.try_emplace(Name, RealPathNames.size());
96 RealPathNames.emplace_back();
97 return R.first->getValue();
100 llvm::StringMap<unsigned>
103 llvm::StringMap<unsigned>
Result;
105 std::vector<unsigned> CurrentLevel;
106 llvm::DenseSet<unsigned> Seen;
107 auto It = NameToIndex.find(Root);
108 if (It != NameToIndex.end()) {
109 CurrentLevel.push_back(It->second);
110 Seen.insert(It->second);
114 std::vector<unsigned> PreviousLevel;
115 for (
unsigned Level = 1; !CurrentLevel.empty(); ++Level) {
116 PreviousLevel.clear();
117 PreviousLevel.swap(CurrentLevel);
118 for (
const auto &Parent : PreviousLevel) {
119 for (
const auto &Child : IncludeChildren.lookup(Parent)) {
120 if (Seen.insert(Child).second) {
121 CurrentLevel.push_back(Child);
122 const auto &Name = RealPathNames[Child];
125 Result[Name] = Level;
134 IncludedHeaders.insert(Inc.
Written);
136 IncludedHeaders.insert(Inc.
Resolved);
143 assert(DeclaringHeader.
valid() && InsertedHeader.
valid());
144 if (FileName == DeclaringHeader.
File || FileName == InsertedHeader.
File)
146 auto Included = [&](llvm::StringRef Header) {
147 return IncludedHeaders.find(Header) != IncludedHeaders.end();
149 return !Included(DeclaringHeader.
File) && !Included(InsertedHeader.
File);
155 assert(DeclaringHeader.
valid() && InsertedHeader.
valid());
157 return InsertedHeader.
File;
158 bool IsSystem =
false;
159 std::string Suggested = HeaderSearchInfo.suggestPathToFileForDiagnostics(
160 InsertedHeader.
File, BuildDir, &IsSystem);
162 Suggested =
"<" + Suggested +
">";
164 Suggested =
"\"" + Suggested +
"\"";
168 llvm::Optional<TextEdit>
170 llvm::Optional<TextEdit> Edit =
None;
171 if (
auto Insertion = Inserter.insert(VerbatimHeader.trim(
"\"<>"),
172 VerbatimHeader.startswith(
"<")))
178 return OS << Inc.
Written <<
" = "
Documents should not be synced at all.
llvm::Optional< TextEdit > insert(llvm::StringRef VerbatimHeader) const
Calculates an edit that inserts VerbatimHeader into code.
void addExisting(const Inclusion &Inc)
bool IsAngled
true if this was an include with angle brackets
static constexpr llvm::StringLiteral Name
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
bool shouldInsertInclude(const HeaderFile &DeclaringHeader, const HeaderFile &InsertedHeader) const
Checks whether to add an #include of the header into File.
void recordInclude(llvm::StringRef IncludingName, llvm::StringRef IncludedName, llvm::StringRef IncludedRealName)
std::string calculateIncludePath(const HeaderFile &DeclaringHeader, const HeaderFile &InsertedHeader) const
Determines the preferred way to #include a file, taking into account the search path.
std::unique_ptr< PPCallbacks > collectIncludeStructureCallback(const SourceManager &SM, IncludeStructure *Out)
Returns a PPCallback that visits all inclusions in the main file.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
TextEdit replacementToEdit(llvm::StringRef Code, const tooling::Replacement &R)
llvm::StringMap< unsigned > includeDepth(llvm::StringRef Root) const
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
bool isLiteralInclude(llvm::StringRef Include)
Returns true if Include is literal include like "path" or <path>.
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)