diff options
author | Jordan Rose <jordan_rose@apple.com> | 2013-01-10 18:50:46 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2013-01-10 18:50:46 +0000 |
commit | 98e7369d9ef5e53964cc8ae48ec2dfcf6c4633c0 (patch) | |
tree | 63d8e50e1b9c307e7223e567470130d3e34cf8be /utils | |
parent | 3f8c7f3a07df65580a9ca0fe3e956b8a40956a79 (diff) |
Error if an anonymous DiagGroup is referenced multiple times.
Not only is this inefficient for TableGen, it's annoying for maintenance
when renaming warning flags (unusual) or adding those flags to a group
(more likely).
This uses the new fix-it infrastructure for LLVM's SourceMgr/SMDiagnostic,
as well as a few changes to TableGen to track more source information.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172087 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils')
-rw-r--r-- | utils/TableGen/ClangDiagnosticsEmitter.cpp | 121 |
1 files changed, 119 insertions, 2 deletions
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp index b7b8e09d88..448fb7013f 100644 --- a/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -14,8 +14,12 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/TableGen/Error.h" @@ -127,14 +131,41 @@ namespace { std::vector<const Record*> DiagsInGroup; std::vector<std::string> SubGroups; unsigned IDNo; + + const Record *ExplicitDef; + + GroupInfo() : ExplicitDef(0) {} }; } // end anonymous namespace. +static bool beforeThanCompare(const Record *LHS, const Record *RHS) { + assert(!LHS->getLoc().empty() && !RHS->getLoc().empty()); + return + LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer(); +} + +static bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){ + assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty()); + return beforeThanCompare(LHS->DiagsInGroup.front(), + RHS->DiagsInGroup.front()); +} + +static SMRange findSuperClassRange(const Record *R, StringRef SuperName) { + ArrayRef<Record *> Supers = R->getSuperClasses(); + + for (size_t i = 0, e = Supers.size(); i < e; ++i) + if (Supers[i]->getName() == SuperName) + return R->getSuperClassRanges()[i]; + + return SMRange(); +} + /// \brief Invert the 1-[0/1] mapping of diags to group into a one to many /// mapping of groups to diags in the group. static void groupDiagnostics(const std::vector<Record*> &Diags, const std::vector<Record*> &DiagGroups, std::map<std::string, GroupInfo> &DiagsInGroup) { + for (unsigned i = 0, e = Diags.size(); i != e; ++i) { const Record *R = Diags[i]; DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")); @@ -144,13 +175,25 @@ static void groupDiagnostics(const std::vector<Record*> &Diags, std::string GroupName = DI->getDef()->getValueAsString("GroupName"); DiagsInGroup[GroupName].DiagsInGroup.push_back(R); } - + + typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy; + GroupSetTy ImplicitGroups; + // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty // groups (these are warnings that GCC supports that clang never produces). for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { Record *Group = DiagGroups[i]; GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; - + if (Group->isAnonymous()) { + if (GI.DiagsInGroup.size() > 1) + ImplicitGroups.insert(&GI); + } else { + if (GI.ExplicitDef) + assert(GI.ExplicitDef == Group); + else + GI.ExplicitDef = Group; + } + std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups"); for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName")); @@ -161,6 +204,80 @@ static void groupDiagnostics(const std::vector<Record*> &Diags, for (std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo) I->second.IDNo = IDNo; + + // Sort the implicit groups, so we can warn about them deterministically. + SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(), + ImplicitGroups.end()); + for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(), + E = SortedGroups.end(); + I != E; ++I) { + MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup; + std::sort(GroupDiags.begin(), GroupDiags.end(), beforeThanCompare); + } + std::sort(SortedGroups.begin(), SortedGroups.end(), beforeThanCompareGroups); + + // Warn about the same group being used anonymously in multiple places. + for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(), + E = SortedGroups.end(); + I != E; ++I) { + ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup; + + if ((*I)->ExplicitDef) { + std::string Name = (*I)->ExplicitDef->getValueAsString("GroupName"); + for (ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(), + DE = GroupDiags.end(); + DI != DE; ++DI) { + const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); + const Record *NextDiagGroup = GroupInit->getDef(); + if (NextDiagGroup == (*I)->ExplicitDef) + continue; + + SMRange InGroupRange = findSuperClassRange(*DI, "InGroup"); + SmallString<64> Replacement; + if (InGroupRange.isValid()) { + Replacement += "InGroup<"; + Replacement += (*I)->ExplicitDef->getName(); + Replacement += ">"; + } + SMFixIt FixIt(InGroupRange, Replacement.str()); + + SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(), + SourceMgr::DK_Error, + Twine("group '") + Name + + "' is referred to anonymously", + ArrayRef<SMRange>(), + InGroupRange.isValid() ? FixIt + : ArrayRef<SMFixIt>()); + SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(), + SourceMgr::DK_Note, "group defined here"); + } + } else { + // If there's no existing named group, we should just warn once and use + // notes to list all the other cases. + ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(), + DE = GroupDiags.end(); + assert(DI != DE && "We only care about groups with multiple uses!"); + + const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); + const Record *NextDiagGroup = GroupInit->getDef(); + std::string Name = NextDiagGroup->getValueAsString("GroupName"); + + SMRange InGroupRange = findSuperClassRange(*DI, "InGroup"); + SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(), + SourceMgr::DK_Error, + Twine("group '") + Name + + "' is referred to anonymously", + InGroupRange); + + for (++DI; DI != DE; ++DI) { + GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); + InGroupRange = findSuperClassRange(*DI, "InGroup"); + SrcMgr.PrintMessage(GroupInit->getDef()->getLoc().front(), + SourceMgr::DK_Note, "also referenced here", + InGroupRange); + } + } + } } //===----------------------------------------------------------------------===// |