/// GetMessage - Return an SMDiagnostic at the specified location with the /// specified string. /// /// @param Type - If non-null, the kind of message (e.g., "error") which is /// prefixed to the message. SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg, ArrayRef<SMRange> Ranges) const { // First thing to do: find the current buffer containing the specified // location. int CurBuf = FindBufferContainingLoc(Loc); assert(CurBuf != -1 && "Invalid or unspecified location!"); MemoryBuffer *CurMB = getBufferInfo(CurBuf).Buffer; // Scan backward to find the start of the line. const char *LineStart = Loc.getPointer(); while (LineStart != CurMB->getBufferStart() && LineStart[-1] != '\n' && LineStart[-1] != '\r') --LineStart; // Get the end of the line. const char *LineEnd = Loc.getPointer(); while (LineEnd != CurMB->getBufferEnd() && LineEnd[0] != '\n' && LineEnd[0] != '\r') ++LineEnd; std::string LineStr(LineStart, LineEnd); // Convert any ranges to column ranges that only intersect the line of the // location. SmallVector<std::pair<unsigned, unsigned>, 4> ColRanges; for (unsigned i = 0, e = Ranges.size(); i != e; ++i) { SMRange R = Ranges[i]; if (!R.isValid()) continue; // If the line doesn't contain any part of the range, then ignore it. if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart) continue; // Ignore pieces of the range that go onto other lines. if (R.Start.getPointer() < LineStart) R.Start = SMLoc::getFromPointer(LineStart); if (R.End.getPointer() > LineEnd) R.End = SMLoc::getFromPointer(LineEnd); // Translate from SMLoc ranges to column ranges. ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart, R.End.getPointer()-LineStart)); } return SMDiagnostic(*this, Loc, CurMB->getBufferIdentifier(), FindLineNumber(Loc, CurBuf), Loc.getPointer()-LineStart, Kind, Msg.str(), LineStr, ColRanges); }
SMDiagnostic MIRParserImpl::diagFromLLVMAssemblyDiag(const SMDiagnostic &Error, SMRange SourceRange) { assert(SourceRange.isValid()); // Translate the location of the error from the location in the llvm IR string // to the corresponding location in the MIR file. auto LineAndColumn = SM.getLineAndColumn(SourceRange.Start); unsigned Line = LineAndColumn.first + Error.getLineNo() - 1; unsigned Column = Error.getColumnNo(); StringRef LineStr = Error.getLineContents(); SMLoc Loc = Error.getLoc(); // Get the full line and adjust the column number by taking the indentation of // LLVM IR into account. for (line_iterator L(*SM.getMemoryBuffer(SM.getMainFileID()), false), E; L != E; ++L) { if (L.line_number() == Line) { LineStr = *L; Loc = SMLoc::getFromPointer(LineStr.data()); auto Indent = LineStr.find(Error.getLineContents()); if (Indent != StringRef::npos) Column += Indent; break; } } return SMDiagnostic(SM, Loc, Filename, Line, Column, Error.getKind(), Error.getMessage(), LineStr, Error.getRanges(), Error.getFixIts()); }
SMDiagnostic MIRParserImpl::diagFromMIStringDiag(const SMDiagnostic &Error, SMRange SourceRange) { assert(SourceRange.isValid() && "Invalid source range"); SMLoc Loc = SourceRange.Start; bool HasQuote = Loc.getPointer() < SourceRange.End.getPointer() && *Loc.getPointer() == '\''; // Translate the location of the error from the location in the MI string to // the corresponding location in the MIR file. Loc = Loc.getFromPointer(Loc.getPointer() + Error.getColumnNo() + (HasQuote ? 1 : 0)); // TODO: Translate any source ranges as well. return SM.GetMessage(Loc, Error.getKind(), Error.getMessage(), None, Error.getFixIts()); }
SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg, ArrayRef<SMRange> Ranges, ArrayRef<SMFixIt> FixIts) const { // First thing to do: find the current buffer containing the specified // location to pull out the source line. SmallVector<std::pair<unsigned, unsigned>, 4> ColRanges; std::pair<unsigned, unsigned> LineAndCol; const char *BufferID = "<unknown>"; std::string LineStr; if (Loc.isValid()) { unsigned CurBuf = FindBufferContainingLoc(Loc); assert(CurBuf && "Invalid or unspecified location!"); const MemoryBuffer *CurMB = getMemoryBuffer(CurBuf); BufferID = CurMB->getBufferIdentifier(); // Scan backward to find the start of the line. const char *LineStart = Loc.getPointer(); const char *BufStart = CurMB->getBufferStart(); while (LineStart != BufStart && LineStart[-1] != '\n' && LineStart[-1] != '\r') --LineStart; // Get the end of the line. const char *LineEnd = Loc.getPointer(); const char *BufEnd = CurMB->getBufferEnd(); while (LineEnd != BufEnd && LineEnd[0] != '\n' && LineEnd[0] != '\r') ++LineEnd; LineStr = std::string(LineStart, LineEnd); // Convert any ranges to column ranges that only intersect the line of the // location. for (unsigned i = 0, e = Ranges.size(); i != e; ++i) { SMRange R = Ranges[i]; if (!R.isValid()) continue; // If the line doesn't contain any part of the range, then ignore it. if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart) continue; // Ignore pieces of the range that go onto other lines. if (R.Start.getPointer() < LineStart) R.Start = SMLoc::getFromPointer(LineStart); if (R.End.getPointer() > LineEnd) R.End = SMLoc::getFromPointer(LineEnd); // Translate from SMLoc ranges to column ranges. // FIXME: Handle multibyte characters. ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart, R.End.getPointer()-LineStart)); } LineAndCol = getLineAndColumn(Loc, CurBuf); } return SMDiagnostic(*this, Loc, BufferID, LineAndCol.first, LineAndCol.second-1, Kind, Msg.str(), LineStr, ColRanges, FixIts); }
/// \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")); if (!DI) continue; assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" && "Note can't be in a DiagGroup"); 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")); } // Assign unique ID numbers to the groups. unsigned IDNo = 0; 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", None, 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); } } } }