1//===--- StandaloneDiagnostic.h - Serializable Diagnostic ------------- ---===//
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/Frontend/StandaloneDiagnostic.h"
10#include "clang/Lex/Lexer.h"
11
12namespace clang {
13
14StandaloneDiagnostic::SourceOffsetRange::SourceOffsetRange(
15 CharSourceRange Range, const SourceManager &SrcMgr,
16 const LangOptions &LangOpts) {
17 const auto FileRange = Lexer::makeFileCharRange(Range, SM: SrcMgr, LangOpts);
18 Begin = SrcMgr.getFileOffset(SpellingLoc: FileRange.getBegin());
19 End = SrcMgr.getFileOffset(SpellingLoc: FileRange.getEnd());
20}
21
22StandaloneDiagnostic::StandaloneFixIt::StandaloneFixIt(
23 const SourceManager &SrcMgr, const LangOptions &LangOpts,
24 const FixItHint &FixIt)
25 : RemoveRange(FixIt.RemoveRange, SrcMgr, LangOpts),
26 InsertFromRange(FixIt.InsertFromRange, SrcMgr, LangOpts),
27 CodeToInsert(FixIt.CodeToInsert),
28 BeforePreviousInsertions(FixIt.BeforePreviousInsertions) {}
29
30StandaloneDiagnostic::StandaloneDiagnostic(const LangOptions &LangOpts,
31 const StoredDiagnostic &InDiag)
32 : Level(InDiag.getLevel()), ID(InDiag.getID()),
33 Message(InDiag.getMessage()) {
34 const FullSourceLoc &FullLoc = InDiag.getLocation();
35 // This is not an invalid diagnostic; invalid SourceLocations are used to
36 // represent diagnostics without a specific SourceLocation.
37 if (FullLoc.isInvalid())
38 return;
39
40 const auto &SrcMgr = FullLoc.getManager();
41 FileKind = SrcMgr.getFileCharacteristic(Loc: static_cast<SourceLocation>(FullLoc));
42 const auto FileLoc = SrcMgr.getFileLoc(Loc: static_cast<SourceLocation>(FullLoc));
43 FileOffset = SrcMgr.getFileOffset(SpellingLoc: FileLoc);
44 Filename = SrcMgr.getFilename(SpellingLoc: FileLoc);
45 assert(!Filename.empty() && "diagnostic with location has no source file?");
46
47 Ranges.reserve(n: InDiag.getRanges().size());
48 for (const auto &Range : InDiag.getRanges())
49 Ranges.emplace_back(args: Range, args: SrcMgr, args: LangOpts);
50
51 FixIts.reserve(n: InDiag.getFixIts().size());
52 for (const auto &FixIt : InDiag.getFixIts())
53 FixIts.emplace_back(args: SrcMgr, args: LangOpts, args: FixIt);
54}
55
56StoredDiagnostic
57translateStandaloneDiag(FileManager &FileMgr, SourceManager &SrcMgr,
58 const StandaloneDiagnostic &StandaloneDiag,
59 llvm::StringMap<SourceLocation> &SrcLocCache) {
60 const auto FileRef = FileMgr.getOptionalFileRef(Filename: StandaloneDiag.Filename);
61 if (!FileRef)
62 return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID,
63 StandaloneDiag.Message);
64
65 // Try to get FileLoc from cache first
66 SourceLocation FileLoc;
67 auto It = SrcLocCache.find(Key: StandaloneDiag.Filename);
68 if (It != SrcLocCache.end()) {
69 FileLoc = It->getValue();
70 }
71
72 // Cache miss - compute and cache the location
73 if (FileLoc.isInvalid()) {
74 const auto FileID =
75 SrcMgr.getOrCreateFileID(SourceFile: *FileRef, FileCharacter: StandaloneDiag.FileKind);
76 FileLoc = SrcMgr.getLocForStartOfFile(FID: FileID);
77
78 if (FileLoc.isInvalid())
79 return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID,
80 StandaloneDiag.Message);
81
82 SrcLocCache[StandaloneDiag.Filename] = FileLoc;
83 }
84
85 const auto DiagLoc = FileLoc.getLocWithOffset(Offset: StandaloneDiag.FileOffset);
86 const FullSourceLoc Loc(DiagLoc, SrcMgr);
87
88 auto ConvertOffsetRange =
89 [&](const StandaloneDiagnostic::SourceOffsetRange &Range) {
90 return CharSourceRange(
91 SourceRange(FileLoc.getLocWithOffset(Offset: Range.Begin),
92 FileLoc.getLocWithOffset(Offset: Range.End)),
93 /*IsTokenRange*/ false);
94 };
95
96 SmallVector<CharSourceRange, 4> TranslatedRanges;
97 TranslatedRanges.reserve(N: StandaloneDiag.Ranges.size());
98 transform(Range: StandaloneDiag.Ranges, d_first: std::back_inserter(x&: TranslatedRanges),
99 F: ConvertOffsetRange);
100
101 SmallVector<FixItHint, 2> TranslatedFixIts;
102 TranslatedFixIts.reserve(N: StandaloneDiag.FixIts.size());
103 for (const auto &FixIt : StandaloneDiag.FixIts) {
104 FixItHint TranslatedFixIt;
105 TranslatedFixIt.CodeToInsert = FixIt.CodeToInsert;
106 TranslatedFixIt.RemoveRange = ConvertOffsetRange(FixIt.RemoveRange);
107 TranslatedFixIt.InsertFromRange = ConvertOffsetRange(FixIt.InsertFromRange);
108 TranslatedFixIt.BeforePreviousInsertions = FixIt.BeforePreviousInsertions;
109 TranslatedFixIts.push_back(Elt: std::move(TranslatedFixIt));
110 }
111
112 return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID,
113 StandaloneDiag.Message, Loc, TranslatedRanges,
114 TranslatedFixIts);
115}
116
117} // namespace clang
118