[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:
Alexander Shaposhnikov 2017-06-20 20:46:58 +00:00
parent 67cd347e93
commit 3dbef856d4
3 changed files with 48 additions and 15 deletions

View File

@ -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;

View File

@ -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,9 +74,10 @@ 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) !=
std::tie(U.ImmediateExpansionLoc, U.UseLoc);
}) != I->second.end()) { }) != 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
@ -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);
} }

View File

@ -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());
}