forked from OSchip/llvm-project
Clean up and document code modification hints.
llvm-svn: 65641
This commit is contained in:
parent
7094c15d7e
commit
96977da72c
|
@ -386,6 +386,63 @@ completely independent of how the diagnostic is formatted and in what language
|
|||
it is rendered.
|
||||
</p>
|
||||
|
||||
<!-- ==================================================== -->
|
||||
<h4 id="code-modification-hints">Code Modification Hints</h4>
|
||||
<!-- ==================================================== -->
|
||||
|
||||
<p>In some cases, the front end emits diagnostics when it is clear
|
||||
that some small change to the source code would fix the problem. For
|
||||
example, a missing semicolon at the end of a statement or a use of
|
||||
deprecated syntax that is easily rewritten into a more modern form. In
|
||||
these cases, the front end should emit the diagnostic and recover
|
||||
gracefully.</p>
|
||||
|
||||
<p>In these cases, the diagnostic can be annotation with a code
|
||||
modification "hint" that describes how to modify the code referenced
|
||||
by the diagnostic to fix the problem. For example, it might add the
|
||||
missing semicolon at the end of the statement or rewrite the use of a
|
||||
deprecated construct into something more palatable. Here is one such
|
||||
example C++ front end, where we warn about the right-shift operator
|
||||
changing meaning from C++98 to C++0x:</p>
|
||||
|
||||
<pre>
|
||||
test.cpp:3:7: warning: use of right-shift operator ('>>') in template argument will require parentheses in C++0x
|
||||
A<100 >> 2> *a;
|
||||
^
|
||||
( )
|
||||
</pre>
|
||||
|
||||
<p>Here, the code modification hint is suggesting that parentheses be
|
||||
added, and showing exactly where those parentheses would be inserted
|
||||
into the source code. The code modification hints themselves describe
|
||||
what changes to make to the source code in an abstract manner, which
|
||||
the text diagnostic printer renders as a line of "insertions" below
|
||||
the caret line. <a href="#DiagnosticClient">Other diagnostic
|
||||
clients</a> might choose to render the code differently (e.g., as
|
||||
markup inline) or even give the user the ability to automatically fix
|
||||
the problem.</p>
|
||||
|
||||
<p>All code modification hints are described by the
|
||||
<code>CodeModificationHint</code> class, instances of which should be
|
||||
attached to the diagnostic using the << operator in the same way
|
||||
that highlighted source ranges and arguments are passed to the
|
||||
diagnostic. Code modification hints can be created with one of three
|
||||
constructors:</p>
|
||||
|
||||
<dl>
|
||||
<dt><code>CodeModificationHint::CreateInsertion(Loc, Code)</code></dt>
|
||||
<dd>Specifies that the given <code>Code</code> (a string) should be inserted
|
||||
before the source location <code>Loc</code>.</dd>
|
||||
|
||||
<dt><code>CodeModificationHint::CreateRemoval(Range)</code></dt>
|
||||
<dd>Specifies that the code in the given source <code>Range</code>
|
||||
should be removed.</dd>
|
||||
|
||||
<dt><code>CodeModificationHint::CreateReplacement(Range, Code)</code></dt>
|
||||
<dd>Specifies that the code in the given source <code>Range</code>
|
||||
should be removed, and replaced with the given <code>Code</code> string.</dd>
|
||||
</dl>
|
||||
|
||||
<!-- ============================================================= -->
|
||||
<h4><a name="DiagnosticClient">The DiagnosticClient Interface</a></h4>
|
||||
<!-- ============================================================= -->
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace clang {
|
|||
/// introduction, removal, or modification of a particular (small!)
|
||||
/// amount of code will correct a compilation error. The compiler
|
||||
/// should also provide full recovery from such errors, such that
|
||||
/// suppressing the diagnostic output can still result successful
|
||||
/// suppressing the diagnostic output can still result in successful
|
||||
/// compilation.
|
||||
class CodeModificationHint {
|
||||
public:
|
||||
|
@ -96,41 +96,34 @@ public:
|
|||
|
||||
/// \brief Create a code modification hint that inserts the given
|
||||
/// code string at a specific location.
|
||||
CodeModificationHint(SourceLocation InsertionLoc, const std::string &Code)
|
||||
: RemoveRange(), InsertionLoc(InsertionLoc), CodeToInsert(Code) { }
|
||||
static CodeModificationHint CreateInsertion(SourceLocation InsertionLoc,
|
||||
const std::string &Code) {
|
||||
CodeModificationHint Hint;
|
||||
Hint.InsertionLoc = InsertionLoc;
|
||||
Hint.CodeToInsert = Code;
|
||||
return Hint;
|
||||
}
|
||||
|
||||
/// \brief Create a code modification hint that removes the given
|
||||
/// source range.
|
||||
CodeModificationHint(SourceRange RemoveRange)
|
||||
: RemoveRange(RemoveRange), InsertionLoc(), CodeToInsert() { }
|
||||
static CodeModificationHint CreateRemoval(SourceRange RemoveRange) {
|
||||
CodeModificationHint Hint;
|
||||
Hint.RemoveRange = RemoveRange;
|
||||
return Hint;
|
||||
}
|
||||
|
||||
/// \brief Create a code modification hint that replaces the given
|
||||
/// source range with the given code string.
|
||||
CodeModificationHint(SourceRange RemoveRange, const std::string &Code)
|
||||
: RemoveRange(RemoveRange), InsertionLoc(RemoveRange.getBegin()),
|
||||
CodeToInsert(Code) { }
|
||||
static CodeModificationHint CreateReplacement(SourceRange RemoveRange,
|
||||
const std::string &Code) {
|
||||
CodeModificationHint Hint;
|
||||
Hint.RemoveRange = RemoveRange;
|
||||
Hint.InsertionLoc = RemoveRange.getBegin();
|
||||
Hint.CodeToInsert = Code;
|
||||
return Hint;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Creates a code modification hint that inserts the given
|
||||
/// string at a particular location in the source code.
|
||||
inline CodeModificationHint
|
||||
CodeInsertionHint(SourceLocation InsertionLoc, const std::string &Code) {
|
||||
return CodeModificationHint(InsertionLoc, Code);
|
||||
}
|
||||
|
||||
/// \brief Creates a code modification hint that removes the given
|
||||
/// source range.
|
||||
inline CodeModificationHint CodeRemovalHint(SourceRange RemoveRange) {
|
||||
return CodeModificationHint(RemoveRange);
|
||||
}
|
||||
|
||||
/// \brief Creates a code modification hint that replaces the given
|
||||
/// source range with the given code string.
|
||||
inline CodeModificationHint
|
||||
CodeReplacementHint(SourceRange RemoveRange, const std::string &Code) {
|
||||
return CodeModificationHint(RemoveRange, Code);
|
||||
}
|
||||
|
||||
/// Diagnostic - This concrete class is used by the front-end to report
|
||||
/// problems and issues. It massages the diagnostics (e.g. handling things like
|
||||
/// "report warnings as errors" and passes them off to the DiagnosticClient for
|
||||
|
|
|
@ -43,8 +43,20 @@ enum ObjCKeywordKind {
|
|||
NUM_OBJC_KEYWORDS
|
||||
};
|
||||
|
||||
/// \brief Determines the name of a token as used within the front end.
|
||||
///
|
||||
/// The name of a token will be an internal name (such as "l_square")
|
||||
/// and should not be used as part of diagnostic messages.
|
||||
const char *getTokenName(enum TokenKind Kind);
|
||||
const char *getTokenSpelling(enum TokenKind Kind);
|
||||
|
||||
/// \brief Determines the spelling of simple punctuation tokens like
|
||||
/// '!' or '%', and returns NULL for literal and annotation tokens.
|
||||
///
|
||||
/// This routine only retrieves the "simple" spelling of the token,
|
||||
/// and will not produce any alternative spellings (e.g., a
|
||||
/// digraph). For the actual spelling of a given Token, use
|
||||
/// Preprocessor::getSpelling().
|
||||
const char *getTokenSimpleSpelling(enum TokenKind Kind);
|
||||
|
||||
} // end namespace tok
|
||||
} // end namespace clang
|
||||
|
|
|
@ -476,7 +476,7 @@ public:
|
|||
/// copy). The caller is not allowed to modify the returned buffer pointer
|
||||
/// if an internal buffer is returned.
|
||||
unsigned getSpelling(const Token &Tok, const char *&Buffer) const;
|
||||
|
||||
|
||||
/// getSpellingOfSingleCharacterNumericConstant - Tok is a numeric constant
|
||||
/// with length 1, return the character.
|
||||
char getSpellingOfSingleCharacterNumericConstant(const Token &Tok) const {
|
||||
|
@ -498,7 +498,19 @@ public:
|
|||
/// location provides a location of the instantiation point of the token.
|
||||
void CreateString(const char *Buf, unsigned Len,
|
||||
Token &Tok, SourceLocation SourceLoc = SourceLocation());
|
||||
|
||||
|
||||
/// \brief Computes the source location just past the end of the
|
||||
/// token at this source location.
|
||||
///
|
||||
/// This routine can be used to produce a source location that
|
||||
/// points just past the end of the token referenced by \p Loc, and
|
||||
/// is generally used when a diagnostic needs to point just after a
|
||||
/// token where it expected something different that it received. If
|
||||
/// the returned source location would not be meaningful (e.g., if
|
||||
/// it points into a macro), this routine returns an invalid
|
||||
/// source location.
|
||||
SourceLocation getLocForEndOfToken(SourceLocation Loc);
|
||||
|
||||
/// DumpToken - Print the token to stderr, used for debugging.
|
||||
///
|
||||
void DumpToken(const Token &Tok, bool DumpFlags = false) const;
|
||||
|
|
|
@ -28,9 +28,7 @@ const char *tok::getTokenName(enum TokenKind Kind) {
|
|||
return TokNames[Kind];
|
||||
}
|
||||
|
||||
/// \brief Determines the spelling of simple punctuation tokens like
|
||||
/// '!' or '%', and returns NULL for literal and annotation tokens.
|
||||
const char *tok::getTokenSpelling(enum TokenKind Kind) {
|
||||
const char *tok::getTokenSimpleSpelling(enum TokenKind Kind) {
|
||||
switch (Kind) {
|
||||
case tok::l_square: return "[";
|
||||
case tok::r_square: return "]";
|
||||
|
|
|
@ -265,7 +265,6 @@ unsigned Preprocessor::getSpelling(const Token &Tok,
|
|||
return OutBuf-Buffer;
|
||||
}
|
||||
|
||||
|
||||
/// CreateString - Plop the specified string into a scratch buffer and return a
|
||||
/// location for it. If specified, the source location provides a source
|
||||
/// location for the token.
|
||||
|
@ -321,6 +320,25 @@ SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart,
|
|||
return TokStart.getFileLocWithOffset(PhysOffset);
|
||||
}
|
||||
|
||||
/// \brief Computes the source location just past the end of the
|
||||
/// token at this source location.
|
||||
///
|
||||
/// This routine can be used to produce a source location that
|
||||
/// points just past the end of the token referenced by \p Loc, and
|
||||
/// is generally used when a diagnostic needs to point just after a
|
||||
/// token where it expected something different that it received. If
|
||||
/// the returned source location would not be meaningful (e.g., if
|
||||
/// it points into a macro), this routine returns an invalid
|
||||
/// source location.
|
||||
SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc) {
|
||||
if (Loc.isInvalid() || !Loc.isFileID())
|
||||
return SourceLocation();
|
||||
|
||||
unsigned Len = Lexer::MeasureTokenLength(Loc, getSourceManager());
|
||||
return AdvanceToTokenCharacter(Loc, Len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Preprocessor Initialization Methods
|
||||
|
|
|
@ -445,7 +445,8 @@ Parser::ParseTemplateIdAfterTemplateName(DeclTy *Template,
|
|||
ReplaceStr = "> > ";
|
||||
|
||||
Diag(Tok.getLocation(), diag::err_two_right_angle_brackets_need_space)
|
||||
<< CodeReplacementHint(SourceRange(Tok.getLocation()), ReplaceStr);
|
||||
<< CodeModificationHint::CreateReplacement(
|
||||
SourceRange(Tok.getLocation()), ReplaceStr);
|
||||
}
|
||||
|
||||
Tok.setKind(tok::greater);
|
||||
|
|
|
@ -76,18 +76,17 @@ DiagnosticBuilder Parser::Diag(const Token &Tok, unsigned DiagID) {
|
|||
/// \param ParenRange Source range enclosing code that should be parenthesized.
|
||||
void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK,
|
||||
SourceRange ParenRange) {
|
||||
if (!ParenRange.getEnd().isFileID()) {
|
||||
SourceLocation EndLoc = PP.getLocForEndOfToken(ParenRange.getEnd());
|
||||
if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
|
||||
// We can't display the parentheses, so just dig the
|
||||
// warning/error and return.
|
||||
Diag(Loc, DK);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned Len = Lexer::MeasureTokenLength(ParenRange.getEnd(),
|
||||
PP.getSourceManager());
|
||||
Diag(Loc, DK)
|
||||
<< CodeInsertionHint(ParenRange.getBegin(), "(")
|
||||
<< CodeInsertionHint(ParenRange.getEnd().getFileLocWithOffset(Len), ")");
|
||||
<< CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(")
|
||||
<< CodeModificationHint::CreateInsertion(EndLoc, ")");
|
||||
}
|
||||
|
||||
/// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'),
|
||||
|
@ -131,14 +130,13 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
|
|||
}
|
||||
|
||||
const char *Spelling = 0;
|
||||
if (PrevTokLocation.isValid() && PrevTokLocation.isFileID() &&
|
||||
(Spelling = tok::getTokenSpelling(ExpectedTok))) {
|
||||
SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation);
|
||||
if (EndLoc.isValid() &&
|
||||
(Spelling = tok::getTokenSimpleSpelling(ExpectedTok))) {
|
||||
// Show what code to insert to fix this problem.
|
||||
SourceLocation DiagLoc
|
||||
= PrevTokLocation.getFileLocWithOffset(strlen(Spelling));
|
||||
Diag(DiagLoc, DiagID)
|
||||
Diag(EndLoc, DiagID)
|
||||
<< Msg
|
||||
<< CodeInsertionHint(DiagLoc, Spelling);
|
||||
<< CodeModificationHint::CreateInsertion(EndLoc, Spelling);
|
||||
} else
|
||||
Diag(Tok, DiagID) << Msg;
|
||||
|
||||
|
|
|
@ -1617,7 +1617,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
|||
// template<> headers.
|
||||
if (TemplateParameterLists.size() == 0)
|
||||
Diag(KWLoc, diag::err_template_spec_needs_header)
|
||||
<< CodeInsertionHint(KWLoc, "template<> ");
|
||||
<< CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
|
||||
else {
|
||||
TemplateParameterList *TemplateParams
|
||||
= static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
|
||||
|
|
Loading…
Reference in New Issue