13 #include "clang/Frontend/CompilerInstance.h" 14 #include "clang/Frontend/CompilerInvocation.h" 15 #include "clang/Frontend/FrontendActions.h" 16 #include "clang/Lex/HeaderSearch.h" 17 #include "llvm/ADT/StringRef.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));
78 llvm::StringRef HintPath) {
87 return IncludePath.takeError();
88 if (!IncludePath->empty())
89 return HeaderFile{std::move(*IncludePath),
true};
93 return Resolved.takeError();
94 return HeaderFile{std::move(*Resolved),
false};
106 llvm::SmallVector<llvm::StringRef, 1> Headers;
107 for (
const auto &Include : Includes)
108 Headers.push_back(Include.IncludeHeader);
112 std::unique_ptr<PPCallbacks>
115 return llvm::make_unique<RecordHeaders>(SM, Out);
119 llvm::StringRef IncludedName,
120 llvm::StringRef IncludedRealName) {
121 auto Child = fileIndex(IncludedName);
122 if (!IncludedRealName.empty() && RealPathNames[Child].empty())
123 RealPathNames[Child] = IncludedRealName;
124 auto Parent = fileIndex(IncludingName);
125 IncludeChildren[Parent].push_back(Child);
128 unsigned IncludeStructure::fileIndex(llvm::StringRef
Name) {
129 auto R = NameToIndex.try_emplace(Name, RealPathNames.size());
131 RealPathNames.emplace_back();
132 return R.first->getValue();
135 llvm::StringMap<unsigned>
138 llvm::StringMap<unsigned>
Result;
140 std::vector<unsigned> CurrentLevel;
141 llvm::DenseSet<unsigned> Seen;
142 auto It = NameToIndex.find(Root);
143 if (It != NameToIndex.end()) {
144 CurrentLevel.push_back(It->second);
145 Seen.insert(It->second);
149 std::vector<unsigned> PreviousLevel;
150 for (
unsigned Level = 1; !CurrentLevel.empty(); ++Level) {
151 PreviousLevel.clear();
152 PreviousLevel.swap(CurrentLevel);
153 for (
const auto &Parent : PreviousLevel) {
154 for (
const auto &Child : IncludeChildren.lookup(Parent)) {
155 if (Seen.insert(Child).second) {
156 CurrentLevel.push_back(Child);
157 const auto &Name = RealPathNames[Child];
160 Result[Name] = Level;
169 IncludedHeaders.insert(Inc.
Written);
171 IncludedHeaders.insert(Inc.
Resolved);
178 assert(InsertedHeader.
valid());
179 if (!HeaderSearchInfo && !InsertedHeader.
Verbatim)
181 if (FileName == DeclaringHeader || FileName == InsertedHeader.
File)
183 auto Included = [&](llvm::StringRef Header) {
184 return IncludedHeaders.find(Header) != IncludedHeaders.end();
186 return !Included(DeclaringHeader) && !Included(InsertedHeader.
File);
189 llvm::Optional<std::string>
191 llvm::StringRef IncludingFile)
const {
192 assert(InsertedHeader.
valid());
194 return InsertedHeader.
File;
195 bool IsSystem =
false;
196 std::string Suggested;
197 if (HeaderSearchInfo) {
198 Suggested = HeaderSearchInfo->suggestPathToFileForDiagnostics(
199 InsertedHeader.
File, BuildDir, IncludingFile, &IsSystem);
202 StringRef IncludingDir = llvm::sys::path::parent_path(IncludingFile);
203 SmallString<256> RelFile(InsertedHeader.
File);
205 llvm::sys::path::replace_path_prefix(RelFile, IncludingDir,
"./");
206 Suggested = llvm::sys::path::convert_to_slash(
207 llvm::sys::path::remove_leading_dotslash(RelFile));
210 if (llvm::sys::path::is_absolute(Suggested))
213 Suggested =
"<" + Suggested +
">";
215 Suggested =
"\"" + Suggested +
"\"";
219 llvm::Optional<TextEdit>
221 llvm::Optional<TextEdit> Edit =
None;
222 if (
auto Insertion = Inserter.insert(VerbatimHeader.trim(
"\"<>"),
223 VerbatimHeader.startswith(
"<")))
229 return OS << Inc.
Written <<
" = "
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Documents should not be synced at all.
llvm::Optional< TextEdit > insert(llvm::StringRef VerbatimHeader) const
Calculates an edit that inserts VerbatimHeader into code.
llvm::SmallVector< IncludeHeaderWithReferences, 1 > IncludeHeaders
One Symbol can potentially be incuded via different headers.
void addExisting(const Inclusion &Inc)
bool IsAngled
true if this was an include with angle brackets
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.
static constexpr llvm::StringLiteral Name
void recordInclude(llvm::StringRef IncludingName, llvm::StringRef IncludedName, llvm::StringRef IncludedRealName)
The class presents a C++ symbol, e.g.
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::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.
llvm::SmallVector< llvm::StringRef, 1 > getRankedIncludes(const Symbol &Sym)
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
static llvm::Expected< std::string > resolve(const URI &U, llvm::StringRef HintPath="")
Resolves the absolute path of U.
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< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
bool shouldInsertInclude(PathRef DeclaringHeader, const HeaderFile &InsertedHeader) const
Checks whether to add an #include of the header into File.
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)