namespace llvm {
template <typename T> class SmallVectorImpl;
- class raw_ostream;
}
namespace clang {
class LangOptions;
class PartialDiagnostic;
class Preprocessor;
- class SourceManager;
- class SourceRange;
// Import the diagnostic enums themselves.
namespace diag {
/// compilation.
class FixItHint {
public:
- /// \brief Tokens that should be removed to correct the error.
- SourceRange RemoveRange;
+ /// \brief Code that should be removed to correct the error.
+ CharSourceRange RemoveRange;
/// \brief The location at which we should insert code to correct
/// the error.
/// \brief Create a code modification hint that removes the given
/// source range.
- static FixItHint CreateRemoval(SourceRange RemoveRange) {
+ static FixItHint CreateRemoval(CharSourceRange RemoveRange) {
FixItHint Hint;
Hint.RemoveRange = RemoveRange;
return Hint;
}
-
+ static FixItHint CreateRemoval(SourceRange RemoveRange) {
+ return CreateRemoval(CharSourceRange::getTokenRange(RemoveRange));
+ }
+
/// \brief Create a code modification hint that replaces the given
/// source range with the given code string.
- static FixItHint CreateReplacement(SourceRange RemoveRange,
+ static FixItHint CreateReplacement(CharSourceRange RemoveRange,
llvm::StringRef Code) {
FixItHint Hint;
Hint.RemoveRange = RemoveRange;
Hint.CodeToInsert = Code;
return Hint;
}
+
+ static FixItHint CreateReplacement(SourceRange RemoveRange,
+ llvm::StringRef Code) {
+ return CreateReplacement(CharSourceRange::getTokenRange(RemoveRange), Code);
+ }
};
/// Diagnostic - This concrete class is used by the front-end to report
/// DiagRanges - The list of ranges added to this diagnostic. It currently
/// only support 10 ranges, could easily be extended if needed.
- SourceRange DiagRanges[10];
+ CharSourceRange DiagRanges[10];
enum { MaxFixItHints = 3 };
}
}
- void AddSourceRange(const SourceRange &R) const {
+ void AddSourceRange(const CharSourceRange &R) const {
assert(NumRanges <
sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) &&
"Too many arguments to diagnostic!");
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const SourceRange &R) {
- DB.AddSourceRange(R);
+ DB.AddSourceRange(CharSourceRange::getTokenRange(R));
return DB;
}
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const CharSourceRange &R) {
+ DB.AddSourceRange(R);
+ return DB;
+}
+
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const FixItHint &Hint) {
DB.AddFixItHint(Hint);
return DiagObj->NumDiagRanges;
}
- SourceRange getRange(unsigned Idx) const {
+ const CharSourceRange &getRange(unsigned Idx) const {
assert(Idx < DiagObj->NumDiagRanges && "Invalid diagnostic range index!");
return DiagObj->DiagRanges[Idx];
}
Diagnostic::Level Level;
FullSourceLoc Loc;
std::string Message;
- std::vector<SourceRange> Ranges;
+ std::vector<CharSourceRange> Ranges;
std::vector<FixItHint> FixIts;
public:
const FullSourceLoc &getLocation() const { return Loc; }
llvm::StringRef getMessage() const { return Message; }
- typedef std::vector<SourceRange>::const_iterator range_iterator;
+ typedef std::vector<CharSourceRange>::const_iterator range_iterator;
range_iterator range_begin() const { return Ranges.begin(); }
range_iterator range_end() const { return Ranges.end(); }
unsigned range_size() const { return Ranges.size(); }
/// DiagRanges - The list of ranges added to this diagnostic. It currently
/// only support 10 ranges, could easily be extended if needed.
- SourceRange DiagRanges[10];
+ CharSourceRange DiagRanges[10];
enum { MaxFixItHints = 3 };
DiagStorage = 0;
}
- void AddSourceRange(const SourceRange &R) const {
+ void AddSourceRange(const CharSourceRange &R) const {
if (!DiagStorage)
DiagStorage = getStorage();
friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
const SourceRange &R) {
- PD.AddSourceRange(R);
+ PD.AddSourceRange(CharSourceRange::getTokenRange(R));
return PD;
}
+ friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+ const CharSourceRange &R) {
+ PD.AddSourceRange(R);
+ return PD;
+ }
+
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
const FixItHint &Hint) {
PD.AddFixItHint(Hint);
return B != X.B || E != X.E;
}
};
+
+/// CharSourceRange - This class represents a character granular source range.
+/// The underlying SourceRange can either specify the starting/ending character
+/// of the range, or it can specify the start or the range and the start of the
+/// last token of the range (a "token range"). In the token range case, the
+/// size of the last token must be measured to determine the actual end of the
+/// range.
+class CharSourceRange {
+ SourceRange Range;
+ bool IsTokenRange;
+public:
+ CharSourceRange() : IsTokenRange(false) {}
+ CharSourceRange(SourceRange R, bool ITR) : Range(R),IsTokenRange(ITR){}
+
+ static CharSourceRange getTokenRange(SourceRange R) {
+ CharSourceRange Result;
+ Result.Range = R;
+ Result.IsTokenRange = true;
+ return Result;
+ }
+
+ static CharSourceRange getCharRange(SourceRange R) {
+ CharSourceRange Result;
+ Result.Range = R;
+ Result.IsTokenRange = false;
+ return Result;
+ }
+
+ static CharSourceRange getTokenRange(SourceLocation B, SourceLocation E) {
+ return getTokenRange(SourceRange(B, E));
+ }
+ static CharSourceRange getCharRange(SourceLocation B, SourceLocation E) {
+ return getCharRange(SourceRange(B, E));
+ }
+
+ /// isTokenRange - Return true if the end of this range specifies the start of
+ /// the last token. Return false if the end of this range specifies the last
+ /// character in the range.
+ bool isTokenRange() const { return IsTokenRange; }
+
+ SourceLocation getBegin() const { return Range.getBegin(); }
+ SourceLocation getEnd() const { return Range.getEnd(); }
+ const SourceRange &getAsRange() const { return Range; }
+
+ void setBegin(SourceLocation b) { Range.setBegin(b); }
+ void setEnd(SourceLocation e) { Range.setEnd(e); }
+
+ bool isValid() const { return Range.isValid(); }
+ bool isInvalid() const { return !isValid(); }
+};
/// FullSourceLoc - A SourceLocation and its associated SourceManager. Useful
/// for argument passing to functions that expect both objects.
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
-namespace llvm {
- class raw_ostream;
-}
-
namespace clang {
class DiagnosticOptions;
class LangOptions;
-class SourceManager;
class TextDiagnosticPrinter : public DiagnosticClient {
llvm::raw_ostream &OS;
void PrintIncludeStack(SourceLocation Loc, const SourceManager &SM);
- void HighlightRange(const SourceRange &R,
+ void HighlightRange(const CharSourceRange &R,
const SourceManager &SrcMgr,
unsigned LineNo, FileID FID,
std::string &CaretLine,
const std::string &SourceLine);
void EmitCaretDiagnostic(SourceLocation Loc,
- SourceRange *Ranges, unsigned NumRanges,
+ CharSourceRange *Ranges, unsigned NumRanges,
const SourceManager &SM,
const FixItHint *Hints,
unsigned NumHints,
/// getRangeSize - Return the size in bytes of the specified range if they
/// are in the same file. If not, this returns -1.
int getRangeSize(SourceRange Range) const;
+ int getRangeSize(const CharSourceRange &Range) const;
/// getRewrittenText - Return the rewritten form of the text in the specified
/// range. If the start or end of the range was unrewritable or if they are
StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level,
const DiagnosticInfo &Info)
- : Level(Level), Loc(Info.getLocation())
-{
+ : Level(Level), Loc(Info.getLocation()) {
llvm::SmallString<64> Message;
Info.FormatDiagnostic(Message);
this->Message.assign(Message.begin(), Message.end());
WriteSourceLocation(OS, SM, R->getBegin());
WriteSourceLocation(OS, SM, R->getEnd());
+ WriteUnsigned(OS, R->isTokenRange());
}
}
for (fixit_iterator F = fixit_begin(), FEnd = fixit_end(); F != FEnd; ++F) {
WriteSourceLocation(OS, SM, F->RemoveRange.getBegin());
WriteSourceLocation(OS, SM, F->RemoveRange.getEnd());
+ WriteUnsigned(OS, F->RemoveRange.isTokenRange());
WriteSourceLocation(OS, SM, F->InsertionLoc);
WriteString(OS, F->CodeToInsert);
}
return Diag;
for (unsigned I = 0; I != NumSourceRanges; ++I) {
SourceLocation Begin, End;
+ unsigned IsTokenRange;
if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Begin) ||
- ReadSourceLocation(FM, SM, Memory, MemoryEnd, End))
+ ReadSourceLocation(FM, SM, Memory, MemoryEnd, End) ||
+ ReadUnsigned(Memory, MemoryEnd, IsTokenRange))
return Diag;
- Diag.Ranges.push_back(SourceRange(Begin, End));
+ Diag.Ranges.push_back(CharSourceRange(SourceRange(Begin, End),
+ IsTokenRange));
}
// Read the fix-it hints.
return Diag;
for (unsigned I = 0; I != NumFixIts; ++I) {
SourceLocation RemoveBegin, RemoveEnd, InsertionLoc;
- unsigned InsertLen = 0;
+ unsigned InsertLen = 0, RemoveIsTokenRange;
if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveBegin) ||
ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveEnd) ||
+ ReadUnsigned(Memory, MemoryEnd, RemoveIsTokenRange) ||
ReadSourceLocation(FM, SM, Memory, MemoryEnd, InsertionLoc) ||
ReadUnsigned(Memory, MemoryEnd, InsertLen) ||
Memory + InsertLen > MemoryEnd) {
}
FixItHint Hint;
- Hint.RemoveRange = SourceRange(RemoveBegin, RemoveEnd);
+ Hint.RemoveRange = CharSourceRange(SourceRange(RemoveBegin, RemoveEnd),
+ RemoveIsTokenRange);
Hint.InsertionLoc = InsertionLoc;
Hint.CodeToInsert.assign(Memory, Memory + InsertLen);
Memory += InsertLen;
new PathDiagnosticEventPiece(Info.getLocation(), StrC.str());
for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
- P->addRange(Info.getRange(i));
+ P->addRange(Info.getRange(i).getAsRange());
for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i)
P->addFixItHint(Info.getFixItHint(i));
D->push_front(P);
/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s)
/// any characters in LineNo that intersect the SourceRange.
-void TextDiagnosticPrinter::HighlightRange(const SourceRange &R,
+void TextDiagnosticPrinter::HighlightRange(const CharSourceRange &R,
const SourceManager &SM,
unsigned LineNo, FileID FID,
std::string &CaretLine,
if (EndColNo) {
--EndColNo; // Zero base the col #.
- // Add in the length of the token, so that we cover multi-char tokens.
- EndColNo += Lexer::MeasureTokenLength(End, SM, *LangOpts);
+ // Add in the length of the token, so that we cover multi-char tokens if
+ // this is a token range.
+ if (R.isTokenRange())
+ EndColNo += Lexer::MeasureTokenLength(End, SM, *LangOpts);
} else {
EndColNo = CaretLine.size();
}
}
void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
- SourceRange *Ranges,
+ CharSourceRange *Ranges,
unsigned NumRanges,
const SourceManager &SM,
const FixItHint *Hints,
// Map the ranges.
for (unsigned i = 0; i != NumRanges; ++i) {
- SourceLocation S = Ranges[i].getBegin(), E = Ranges[i].getEnd();
- if (S.isMacroID()) S = SM.getImmediateSpellingLoc(S);
- if (E.isMacroID()) E = SM.getImmediateSpellingLoc(E);
- Ranges[i] = SourceRange(S, E);
+ CharSourceRange &R = Ranges[i];
+ SourceLocation S = R.getBegin(), E = R.getEnd();
+ if (S.isMacroID())
+ R.setBegin(SM.getImmediateSpellingLoc(S));
+ if (E.isMacroID())
+ R.setEnd(SM.getImmediateSpellingLoc(E));
}
if (!Suppressed) {
continue;
// Add in the length of the token, so that we cover multi-char tokens.
- unsigned TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts);
+ unsigned TokSize = 0;
+ if (Info.getRange(i).isTokenRange())
+ TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts);
OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
<< SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
LastCaretDiagnosticWasNote = (Level == Diagnostic::Note);
// Get the ranges into a local array we can hack on.
- SourceRange Ranges[20];
+ CharSourceRange Ranges[20];
unsigned NumRanges = Info.getNumRanges();
assert(NumRanges < 20 && "Out of space");
for (unsigned i = 0; i != NumRanges; ++i)
Ranges[i] = Info.getRange(i);
unsigned NumHints = Info.getNumFixItHints();
- for (unsigned idx = 0; idx < NumHints; ++idx) {
- const FixItHint &Hint = Info.getFixItHint(idx);
+ for (unsigned i = 0; i != NumHints; ++i) {
+ const FixItHint &Hint = Info.getFixItHint(i);
if (Hint.RemoveRange.isValid()) {
assert(NumRanges < 20 && "Out of space");
Ranges[NumRanges++] = Hint.RemoveRange;
/// getRangeSize - Return the size in bytes of the specified range if they
/// are in the same file. If not, this returns -1.
-int Rewriter::getRangeSize(SourceRange Range) const {
+int Rewriter::getRangeSize(const CharSourceRange &Range) const {
if (!isRewritable(Range.getBegin()) ||
!isRewritable(Range.getEnd())) return -1;
// Adjust the end offset to the end of the last token, instead of being the
- // start of the last token.
- EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
+ // start of the last token if this is a token range.
+ if (Range.isTokenRange())
+ EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
return EndOff-StartOff;
}
+int Rewriter::getRangeSize(SourceRange Range) const {
+ return getRangeSize(CharSourceRange::getTokenRange(Range));
+}
+
+
/// getRewrittenText - Return the rewritten form of the text in the specified
/// range. If the start or end of the range was unrewritable or if they are
/// in different buffers, this returns an empty string.
/// does the appropriate translation.
CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
const LangOptions &LangOpts,
- SourceRange R) {
+ const CharSourceRange &R) {
// We want the last character in this location, so we will adjust the
// location accordingly.
// FIXME: How do do this with a macro instantiation location?
SourceLocation EndLoc = R.getEnd();
- if (!EndLoc.isInvalid() && EndLoc.isFileID()) {
+ if (R.isTokenRange() && !EndLoc.isInvalid() && EndLoc.isFileID()) {
unsigned Length = Lexer::MeasureTokenLength(EndLoc, SM, LangOpts);
EndLoc = EndLoc.getFileLocWithOffset(Length);
}
/// does the appropriate translation.
CXSourceRange translateSourceRange(const SourceManager &SM,
const LangOptions &LangOpts,
- SourceRange R);
+ const CharSourceRange &R);
/// \brief Translate a Clang source range into a CIndex source range.
static inline CXSourceRange translateSourceRange(ASTContext &Context,
SourceRange R) {
return translateSourceRange(Context.getSourceManager(),
Context.getLangOptions(),
- R);
+ CharSourceRange::getTokenRange(R));
}
static inline SourceLocation translateSourceLocation(CXSourceLocation L) {