[clang] Fix format specifiers fixits for nested macros
ExpansionLoc was previously calculated incorrectly in the case of nested macros expansions. In this diff we build the stack of expansions where the last one is the actual expansion which should be used for grouping together the edits. The definition of MacroArgUse is adjusted accordingly. Test plan: make check-all Differential revision: https://reviews.llvm.org/D34268 llvm-svn: 305845
This commit is contained in:
parent
67cd347e93
commit
3dbef856d4
|
@ -17,6 +17,7 @@
|
||||||
#include "llvm/ADT/TinyPtrVector.h"
|
#include "llvm/ADT/TinyPtrVector.h"
|
||||||
#include "llvm/Support/Allocator.h"
|
#include "llvm/Support/Allocator.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
class LangOptions;
|
class LangOptions;
|
||||||
|
@ -41,10 +42,20 @@ class EditedSource {
|
||||||
typedef std::map<FileOffset, FileEdit> FileEditsTy;
|
typedef std::map<FileOffset, FileEdit> FileEditsTy;
|
||||||
FileEditsTy FileEdits;
|
FileEditsTy FileEdits;
|
||||||
|
|
||||||
// Location of argument use inside the macro body
|
struct MacroArgUse {
|
||||||
typedef std::pair<IdentifierInfo*, SourceLocation> MacroArgUse;
|
IdentifierInfo *Identifier;
|
||||||
llvm::DenseMap<unsigned, SmallVector<MacroArgUse, 2>>
|
SourceLocation ImmediateExpansionLoc;
|
||||||
ExpansionToArgMap;
|
// Location of argument use inside the top-level macro
|
||||||
|
SourceLocation UseLoc;
|
||||||
|
|
||||||
|
bool operator==(const MacroArgUse &Other) const {
|
||||||
|
return std::tie(Identifier, ImmediateExpansionLoc, UseLoc) ==
|
||||||
|
std::tie(Other.Identifier, Other.ImmediateExpansionLoc,
|
||||||
|
Other.UseLoc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
llvm::DenseMap<unsigned, SmallVector<MacroArgUse, 2>> ExpansionToArgMap;
|
||||||
SmallVector<std::pair<SourceLocation, MacroArgUse>, 2>
|
SmallVector<std::pair<SourceLocation, MacroArgUse>, 2>
|
||||||
CurrCommitMacroArgExps;
|
CurrCommitMacroArgExps;
|
||||||
|
|
||||||
|
|
|
@ -28,13 +28,18 @@ void EditedSource::deconstructMacroArgLoc(SourceLocation Loc,
|
||||||
MacroArgUse &ArgUse) {
|
MacroArgUse &ArgUse) {
|
||||||
assert(SourceMgr.isMacroArgExpansion(Loc));
|
assert(SourceMgr.isMacroArgExpansion(Loc));
|
||||||
SourceLocation DefArgLoc = SourceMgr.getImmediateExpansionRange(Loc).first;
|
SourceLocation DefArgLoc = SourceMgr.getImmediateExpansionRange(Loc).first;
|
||||||
ExpansionLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
|
SourceLocation ImmediateExpansionLoc =
|
||||||
|
SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
|
||||||
|
ExpansionLoc = ImmediateExpansionLoc;
|
||||||
|
while (SourceMgr.isMacroBodyExpansion(ExpansionLoc))
|
||||||
|
ExpansionLoc = SourceMgr.getImmediateExpansionRange(ExpansionLoc).first;
|
||||||
SmallString<20> Buf;
|
SmallString<20> Buf;
|
||||||
StringRef ArgName = Lexer::getSpelling(SourceMgr.getSpellingLoc(DefArgLoc),
|
StringRef ArgName = Lexer::getSpelling(SourceMgr.getSpellingLoc(DefArgLoc),
|
||||||
Buf, SourceMgr, LangOpts);
|
Buf, SourceMgr, LangOpts);
|
||||||
ArgUse = {nullptr, SourceLocation()};
|
ArgUse = MacroArgUse{nullptr, SourceLocation(), SourceLocation()};
|
||||||
if (!ArgName.empty())
|
if (!ArgName.empty())
|
||||||
ArgUse = {&IdentTable.get(ArgName), SourceMgr.getSpellingLoc(DefArgLoc)};
|
ArgUse = {&IdentTable.get(ArgName), ImmediateExpansionLoc,
|
||||||
|
SourceMgr.getSpellingLoc(DefArgLoc)};
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditedSource::startingCommit() {}
|
void EditedSource::startingCommit() {}
|
||||||
|
@ -69,10 +74,11 @@ bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
|
||||||
deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
|
deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
|
||||||
auto I = ExpansionToArgMap.find(ExpLoc.getRawEncoding());
|
auto I = ExpansionToArgMap.find(ExpLoc.getRawEncoding());
|
||||||
if (I != ExpansionToArgMap.end() &&
|
if (I != ExpansionToArgMap.end() &&
|
||||||
std::find_if(
|
find_if(I->second, [&](const MacroArgUse &U) {
|
||||||
I->second.begin(), I->second.end(), [&](const MacroArgUse &U) {
|
return ArgUse.Identifier == U.Identifier &&
|
||||||
return ArgUse.first == U.first && ArgUse.second != U.second;
|
std::tie(ArgUse.ImmediateExpansionLoc, ArgUse.UseLoc) !=
|
||||||
}) != I->second.end()) {
|
std::tie(U.ImmediateExpansionLoc, U.UseLoc);
|
||||||
|
}) != I->second.end()) {
|
||||||
// Trying to write in a macro argument input that has already been
|
// Trying to write in a macro argument input that has already been
|
||||||
// written by a previous commit for another expansion of the same macro
|
// written by a previous commit for another expansion of the same macro
|
||||||
// argument name. For example:
|
// argument name. For example:
|
||||||
|
@ -89,7 +95,6 @@ bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,10 +107,10 @@ bool EditedSource::commitInsert(SourceLocation OrigLoc,
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
|
if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
|
||||||
SourceLocation ExpLoc;
|
|
||||||
MacroArgUse ArgUse;
|
MacroArgUse ArgUse;
|
||||||
|
SourceLocation ExpLoc;
|
||||||
deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
|
deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
|
||||||
if (ArgUse.first)
|
if (ArgUse.Identifier)
|
||||||
CurrCommitMacroArgExps.emplace_back(ExpLoc, ArgUse);
|
CurrCommitMacroArgExps.emplace_back(ExpLoc, ArgUse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,3 +57,20 @@ void test() {
|
||||||
Log3("test 7: %s", getNSInteger(), getNSUInteger());
|
Log3("test 7: %s", getNSInteger(), getNSUInteger());
|
||||||
// CHECK: Log3("test 7: %ld", (long)getNSInteger(), (unsigned long)getNSUInteger());
|
// CHECK: Log3("test 7: %ld", (long)getNSInteger(), (unsigned long)getNSUInteger());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define Outer1(...) \
|
||||||
|
do { \
|
||||||
|
printf(__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define Outer2(...) \
|
||||||
|
do { \
|
||||||
|
Outer1(__VA_ARGS__); Outer1(__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
void bug33447() {
|
||||||
|
Outer2("test 8: %s", getNSInteger());
|
||||||
|
// CHECK: Outer2("test 8: %ld", (long)getNSInteger());
|
||||||
|
Outer2("test 9: %s %s", getNSInteger(), getNSInteger());
|
||||||
|
// CHECK: Outer2("test 9: %ld %ld", (long)getNSInteger(), (long)getNSInteger());
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue