Next step toward making string diagnostics correct: handle

escapes in the string for subtoken positioning.  This gives
us working examples like:

t.m:5:16: warning: field width should have type 'int', but argument has type 'unsigned int'
  printf("\n\n%*d", (unsigned) 1, 1);
               ^    ~~~~~~~~~~~~

where before the caret pointed two spaces to the left.

llvm-svn: 64940
This commit is contained in:
Chris Lattner 2009-02-18 19:21:10 +00:00
parent 57a09cfcbc
commit ddb7191920
3 changed files with 60 additions and 5 deletions

View File

@ -156,6 +156,12 @@ public:
const char *GetString() { return &ResultBuf[0]; }
unsigned GetStringLength() { return ResultPtr-&ResultBuf[0]; }
/// getOffsetOfStringByte - This function returns the offset of the
/// specified byte of the string data represented by Token. This handles
/// advancing over escape sequences in the string.
static unsigned getOffsetOfStringByte(const Token &TheTok, unsigned ByteNo,
Preprocessor &PP);
};
} // end namespace clang

View File

@ -798,3 +798,49 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
return;
}
}
/// getOffsetOfStringByte - This function returns the offset of the
/// specified byte of the string data represented by Token. This handles
/// advancing over escape sequences in the string.
unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
unsigned ByteNo,
Preprocessor &PP) {
// Get the spelling of the token.
llvm::SmallString<16> SpellingBuffer;
SpellingBuffer.resize(Tok.getLength());
const char *SpellingPtr = &SpellingBuffer[0];
unsigned TokLen = PP.getSpelling(Tok, SpellingPtr);
assert(SpellingPtr[0] != 'L' && "Doesn't handle wide strings yet");
const char *SpellingStart = SpellingPtr;
const char *SpellingEnd = SpellingPtr+TokLen;
// Skip over the leading quote.
assert(SpellingPtr[0] == '"' && "Should be a string literal!");
++SpellingPtr;
// Skip over bytes until we find the offset we're looking for.
while (ByteNo) {
assert(SpellingPtr < SpellingEnd && "Didn't find byte offset!");
// Step over non-escapes simply.
if (*SpellingPtr != '\\') {
++SpellingPtr;
--ByteNo;
continue;
}
// Otherwise, this is an escape character. Advance over it.
bool HadError = false;
ProcessCharEscape(SpellingPtr, SpellingEnd, HadError,
Tok.getLocation(), false, PP);
assert(!HadError && "This method isn't valid on erroneous strings");
--ByteNo;
}
return SpellingPtr-SpellingStart;
}

View File

@ -17,6 +17,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
using namespace clang;
@ -31,7 +32,7 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
unsigned ByteNo) const {
assert(!SL->isWide() && "This doesn't work for wide strings yet");
llvm::SmallString<32> SpellingBuffer;
llvm::SmallString<16> SpellingBuffer;
// Loop over all of the tokens in this string until we find the one that
// contains the byte we're looking for.
@ -78,13 +79,15 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
// The length of the string is the token length minus the two quotes.
TokNumBytes -= 2;
// FIXME: This should consider character escapes!
// If the byte is in this token, return the location of the byte.
if (ByteNo < TokNumBytes ||
(ByteNo == TokNumBytes && TokNo == SL->getNumConcatenated())) {
// We advance +1 to step over the '"'.
return PP.AdvanceToTokenCharacter(StrTokLoc, ByteNo+1);
unsigned Offset =
StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP);
// Now that we know the offset of the token in the spelling, use the
// preprocessor to get the offset in the original source.
return PP.AdvanceToTokenCharacter(StrTokLoc, Offset);
}
// Move to the next string token.