mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-18 22:36:06 +00:00
Enhance Lexer::makeFileCharRange to check for ranges inside a macro argument
expansion, in which case it returns a file range in the location where the argument was spelled. llvm-svn: 148551
This commit is contained in:
parent
528f56c93f
commit
85e7671b71
@ -30,6 +30,7 @@
|
|||||||
#include "clang/Lex/CodeCompletionHandler.h"
|
#include "clang/Lex/CodeCompletionHandler.h"
|
||||||
#include "clang/Basic/SourceManager.h"
|
#include "clang/Basic/SourceManager.h"
|
||||||
#include "llvm/ADT/StringSwitch.h"
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@ -792,6 +793,30 @@ bool Lexer::isAtEndOfMacroExpansion(SourceLocation loc,
|
|||||||
return isAtEndOfMacroExpansion(expansionLoc, SM, LangOpts, MacroEnd);
|
return isAtEndOfMacroExpansion(expansionLoc, SM, LangOpts, MacroEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CharSourceRange makeRangeFromFileLocs(SourceLocation Begin,
|
||||||
|
SourceLocation End,
|
||||||
|
const SourceManager &SM,
|
||||||
|
const LangOptions &LangOpts) {
|
||||||
|
assert(Begin.isFileID() && End.isFileID());
|
||||||
|
End = Lexer::getLocForEndOfToken(End, 0, SM,LangOpts);
|
||||||
|
if (End.isInvalid())
|
||||||
|
return CharSourceRange();
|
||||||
|
|
||||||
|
// Break down the source locations.
|
||||||
|
FileID FID;
|
||||||
|
unsigned BeginOffs;
|
||||||
|
llvm::tie(FID, BeginOffs) = SM.getDecomposedLoc(Begin);
|
||||||
|
if (FID.isInvalid())
|
||||||
|
return CharSourceRange();
|
||||||
|
|
||||||
|
unsigned EndOffs;
|
||||||
|
if (!SM.isInFileID(End, FID, &EndOffs) ||
|
||||||
|
BeginOffs > EndOffs)
|
||||||
|
return CharSourceRange();
|
||||||
|
|
||||||
|
return CharSourceRange::getCharRange(Begin, End);
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Accepts a token source range and returns a character range with
|
/// \brief Accepts a token source range and returns a character range with
|
||||||
/// file locations.
|
/// file locations.
|
||||||
/// Returns a null range if a part of the range resides inside a macro
|
/// Returns a null range if a part of the range resides inside a macro
|
||||||
@ -800,28 +825,53 @@ CharSourceRange Lexer::makeFileCharRange(SourceRange TokenRange,
|
|||||||
const SourceManager &SM,
|
const SourceManager &SM,
|
||||||
const LangOptions &LangOpts) {
|
const LangOptions &LangOpts) {
|
||||||
SourceLocation Begin = TokenRange.getBegin();
|
SourceLocation Begin = TokenRange.getBegin();
|
||||||
if (Begin.isInvalid())
|
SourceLocation End = TokenRange.getEnd();
|
||||||
|
if (Begin.isInvalid() || End.isInvalid())
|
||||||
return CharSourceRange();
|
return CharSourceRange();
|
||||||
|
|
||||||
if (Begin.isMacroID())
|
if (Begin.isFileID() && End.isFileID())
|
||||||
|
return makeRangeFromFileLocs(Begin, End, SM, LangOpts);
|
||||||
|
|
||||||
|
if (Begin.isMacroID() && End.isFileID()) {
|
||||||
if (!isAtStartOfMacroExpansion(Begin, SM, LangOpts, &Begin))
|
if (!isAtStartOfMacroExpansion(Begin, SM, LangOpts, &Begin))
|
||||||
return CharSourceRange();
|
return CharSourceRange();
|
||||||
|
return makeRangeFromFileLocs(Begin, End, SM, LangOpts);
|
||||||
|
}
|
||||||
|
|
||||||
SourceLocation End = getLocForEndOfToken(TokenRange.getEnd(), 0, SM,LangOpts);
|
if (Begin.isFileID() && End.isMacroID()) {
|
||||||
if (End.isInvalid())
|
if (!isAtEndOfMacroExpansion(End, SM, LangOpts, &End))
|
||||||
return CharSourceRange();
|
return CharSourceRange();
|
||||||
|
return makeRangeFromFileLocs(Begin, End, SM, LangOpts);
|
||||||
|
}
|
||||||
|
|
||||||
// Break down the source locations.
|
assert(Begin.isMacroID() && End.isMacroID());
|
||||||
std::pair<FileID, unsigned> beginInfo = SM.getDecomposedLoc(Begin);
|
SourceLocation MacroBegin, MacroEnd;
|
||||||
if (beginInfo.first.isInvalid())
|
if (isAtStartOfMacroExpansion(Begin, SM, LangOpts, &MacroBegin) &&
|
||||||
|
isAtEndOfMacroExpansion(End, SM, LangOpts, &MacroEnd))
|
||||||
|
return makeRangeFromFileLocs(MacroBegin, MacroEnd, SM, LangOpts);
|
||||||
|
|
||||||
|
FileID FID;
|
||||||
|
unsigned BeginOffs;
|
||||||
|
llvm::tie(FID, BeginOffs) = SM.getDecomposedLoc(Begin);
|
||||||
|
if (FID.isInvalid())
|
||||||
return CharSourceRange();
|
return CharSourceRange();
|
||||||
|
|
||||||
unsigned EndOffs;
|
unsigned EndOffs;
|
||||||
if (!SM.isInFileID(End, beginInfo.first, &EndOffs) ||
|
if (!SM.isInFileID(End, FID, &EndOffs) ||
|
||||||
beginInfo.second > EndOffs)
|
BeginOffs > EndOffs)
|
||||||
return CharSourceRange();
|
return CharSourceRange();
|
||||||
|
|
||||||
return CharSourceRange::getCharRange(Begin, End);
|
const SrcMgr::SLocEntry *E = &SM.getSLocEntry(FID);
|
||||||
|
const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
|
||||||
|
if (Expansion.isMacroArgExpansion() &&
|
||||||
|
Expansion.getSpellingLoc().isFileID()) {
|
||||||
|
SourceLocation SpellLoc = Expansion.getSpellingLoc();
|
||||||
|
return makeRangeFromFileLocs(SpellLoc.getLocWithOffset(BeginOffs),
|
||||||
|
SpellLoc.getLocWithOffset(EndOffs),
|
||||||
|
SM, LangOpts);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CharSourceRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef Lexer::getSourceText(CharSourceRange Range,
|
StringRef Lexer::getSourceText(CharSourceRange Range,
|
||||||
|
@ -58,7 +58,8 @@ class VoidModuleLoader : public ModuleLoader {
|
|||||||
TEST_F(LexerTest, LexAPI) {
|
TEST_F(LexerTest, LexAPI) {
|
||||||
const char *source =
|
const char *source =
|
||||||
"#define M(x) [x]\n"
|
"#define M(x) [x]\n"
|
||||||
"M(foo)";
|
"#define N(x) x\n"
|
||||||
|
"M(foo) N([bar])";
|
||||||
MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source);
|
MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source);
|
||||||
SourceMgr.createMainFileIDForMemBuffer(buf);
|
SourceMgr.createMainFileIDForMemBuffer(buf);
|
||||||
|
|
||||||
@ -82,10 +83,13 @@ TEST_F(LexerTest, LexAPI) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we got the tokens that we expected.
|
// Make sure we got the tokens that we expected.
|
||||||
ASSERT_EQ(3U, toks.size());
|
ASSERT_EQ(6U, toks.size());
|
||||||
ASSERT_EQ(tok::l_square, toks[0].getKind());
|
ASSERT_EQ(tok::l_square, toks[0].getKind());
|
||||||
ASSERT_EQ(tok::identifier, toks[1].getKind());
|
ASSERT_EQ(tok::identifier, toks[1].getKind());
|
||||||
ASSERT_EQ(tok::r_square, toks[2].getKind());
|
ASSERT_EQ(tok::r_square, toks[2].getKind());
|
||||||
|
ASSERT_EQ(tok::l_square, toks[3].getKind());
|
||||||
|
ASSERT_EQ(tok::identifier, toks[4].getKind());
|
||||||
|
ASSERT_EQ(tok::r_square, toks[5].getKind());
|
||||||
|
|
||||||
SourceLocation lsqrLoc = toks[0].getLocation();
|
SourceLocation lsqrLoc = toks[0].getLocation();
|
||||||
SourceLocation idLoc = toks[1].getLocation();
|
SourceLocation idLoc = toks[1].getLocation();
|
||||||
@ -119,6 +123,34 @@ TEST_F(LexerTest, LexAPI) {
|
|||||||
CharSourceRange::getTokenRange(SourceRange(lsqrLoc, rsqrLoc)),
|
CharSourceRange::getTokenRange(SourceRange(lsqrLoc, rsqrLoc)),
|
||||||
SourceMgr, LangOpts);
|
SourceMgr, LangOpts);
|
||||||
EXPECT_EQ(text, "M(foo)");
|
EXPECT_EQ(text, "M(foo)");
|
||||||
|
|
||||||
|
SourceLocation macroLsqrLoc = toks[3].getLocation();
|
||||||
|
SourceLocation macroIdLoc = toks[4].getLocation();
|
||||||
|
SourceLocation macroRsqrLoc = toks[5].getLocation();
|
||||||
|
SourceLocation fileLsqrLoc = SourceMgr.getSpellingLoc(macroLsqrLoc);
|
||||||
|
SourceLocation fileIdLoc = SourceMgr.getSpellingLoc(macroIdLoc);
|
||||||
|
SourceLocation fileRsqrLoc = SourceMgr.getSpellingLoc(macroRsqrLoc);
|
||||||
|
|
||||||
|
range = Lexer::makeFileCharRange(SourceRange(macroLsqrLoc, macroIdLoc),
|
||||||
|
SourceMgr, LangOpts);
|
||||||
|
EXPECT_EQ(SourceRange(fileLsqrLoc, fileIdLoc.getLocWithOffset(3)),
|
||||||
|
range.getAsRange());
|
||||||
|
|
||||||
|
range = Lexer::makeFileCharRange(SourceRange(macroIdLoc, macroRsqrLoc),
|
||||||
|
SourceMgr, LangOpts);
|
||||||
|
EXPECT_EQ(SourceRange(fileIdLoc, fileRsqrLoc.getLocWithOffset(1)),
|
||||||
|
range.getAsRange());
|
||||||
|
|
||||||
|
macroPair = SourceMgr.getExpansionRange(macroLsqrLoc);
|
||||||
|
range = Lexer::makeFileCharRange(SourceRange(macroLsqrLoc, macroRsqrLoc),
|
||||||
|
SourceMgr, LangOpts);
|
||||||
|
EXPECT_EQ(SourceRange(macroPair.first, macroPair.second.getLocWithOffset(1)),
|
||||||
|
range.getAsRange());
|
||||||
|
|
||||||
|
text = Lexer::getSourceText(
|
||||||
|
CharSourceRange::getTokenRange(SourceRange(macroLsqrLoc, macroIdLoc)),
|
||||||
|
SourceMgr, LangOpts);
|
||||||
|
EXPECT_EQ(text, "[bar");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
Loading…
x
Reference in New Issue
Block a user