10b57cec5SDimitry Andric //===- Diagnostic.cpp - C Language Family Diagnostic Handling -------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements the Diagnostic-related interfaces. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "clang/Basic/Diagnostic.h" 140b57cec5SDimitry Andric #include "clang/Basic/CharInfo.h" 150b57cec5SDimitry Andric #include "clang/Basic/DiagnosticError.h" 160b57cec5SDimitry Andric #include "clang/Basic/DiagnosticIDs.h" 170b57cec5SDimitry Andric #include "clang/Basic/DiagnosticOptions.h" 180b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h" 190b57cec5SDimitry Andric #include "clang/Basic/PartialDiagnostic.h" 200b57cec5SDimitry Andric #include "clang/Basic/SourceLocation.h" 210b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h" 220b57cec5SDimitry Andric #include "clang/Basic/Specifiers.h" 230b57cec5SDimitry Andric #include "clang/Basic/TokenKinds.h" 240b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 250b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 260b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 270b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 2881ad6265SDimitry Andric #include "llvm/Support/ConvertUTF.h" 290b57cec5SDimitry Andric #include "llvm/Support/CrashRecoveryContext.h" 3081ad6265SDimitry Andric #include "llvm/Support/Unicode.h" 310b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 320b57cec5SDimitry Andric #include <algorithm> 330b57cec5SDimitry Andric #include <cassert> 340b57cec5SDimitry Andric #include <cstddef> 350b57cec5SDimitry Andric #include <cstdint> 360b57cec5SDimitry Andric #include <cstring> 370b57cec5SDimitry Andric #include <limits> 380b57cec5SDimitry Andric #include <string> 390b57cec5SDimitry Andric #include <utility> 400b57cec5SDimitry Andric #include <vector> 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric using namespace clang; 430b57cec5SDimitry Andric 44e8d8bef9SDimitry Andric const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB, 450b57cec5SDimitry Andric DiagNullabilityKind nullability) { 4606c3fb27SDimitry Andric DB.AddString( 4706c3fb27SDimitry Andric ("'" + 4806c3fb27SDimitry Andric getNullabilitySpelling(nullability.first, 4906c3fb27SDimitry Andric /*isContextSensitive=*/nullability.second) + 5006c3fb27SDimitry Andric "'") 5106c3fb27SDimitry Andric .str()); 520b57cec5SDimitry Andric return DB; 530b57cec5SDimitry Andric } 540b57cec5SDimitry Andric 55e8d8bef9SDimitry Andric const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB, 565ffd83dbSDimitry Andric llvm::Error &&E) { 575ffd83dbSDimitry Andric DB.AddString(toString(std::move(E))); 585ffd83dbSDimitry Andric return DB; 595ffd83dbSDimitry Andric } 605ffd83dbSDimitry Andric 610b57cec5SDimitry Andric static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT, 620b57cec5SDimitry Andric StringRef Modifier, StringRef Argument, 630b57cec5SDimitry Andric ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs, 640b57cec5SDimitry Andric SmallVectorImpl<char> &Output, 650b57cec5SDimitry Andric void *Cookie, 660b57cec5SDimitry Andric ArrayRef<intptr_t> QualTypeVals) { 670b57cec5SDimitry Andric StringRef Str = "<can't format argument>"; 680b57cec5SDimitry Andric Output.append(Str.begin(), Str.end()); 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric DiagnosticsEngine::DiagnosticsEngine( 720b57cec5SDimitry Andric IntrusiveRefCntPtr<DiagnosticIDs> diags, 730b57cec5SDimitry Andric IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, DiagnosticConsumer *client, 740b57cec5SDimitry Andric bool ShouldOwnClient) 750b57cec5SDimitry Andric : Diags(std::move(diags)), DiagOpts(std::move(DiagOpts)) { 760b57cec5SDimitry Andric setClient(client, ShouldOwnClient); 770b57cec5SDimitry Andric ArgToStringFn = DummyArgToStringFn; 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric Reset(); 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric DiagnosticsEngine::~DiagnosticsEngine() { 830b57cec5SDimitry Andric // If we own the diagnostic client, destroy it first so that it can access the 840b57cec5SDimitry Andric // engine from its destructor. 850b57cec5SDimitry Andric setClient(nullptr); 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric void DiagnosticsEngine::dump() const { 890b57cec5SDimitry Andric DiagStatesByLoc.dump(*SourceMgr); 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric void DiagnosticsEngine::dump(StringRef DiagName) const { 930b57cec5SDimitry Andric DiagStatesByLoc.dump(*SourceMgr, DiagName); 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric void DiagnosticsEngine::setClient(DiagnosticConsumer *client, 970b57cec5SDimitry Andric bool ShouldOwnClient) { 980b57cec5SDimitry Andric Owner.reset(ShouldOwnClient ? client : nullptr); 990b57cec5SDimitry Andric Client = client; 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric void DiagnosticsEngine::pushMappings(SourceLocation Loc) { 1030b57cec5SDimitry Andric DiagStateOnPushStack.push_back(GetCurDiagState()); 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric bool DiagnosticsEngine::popMappings(SourceLocation Loc) { 1070b57cec5SDimitry Andric if (DiagStateOnPushStack.empty()) 1080b57cec5SDimitry Andric return false; 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric if (DiagStateOnPushStack.back() != GetCurDiagState()) { 1110b57cec5SDimitry Andric // State changed at some point between push/pop. 1120b57cec5SDimitry Andric PushDiagStatePoint(DiagStateOnPushStack.back(), Loc); 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric DiagStateOnPushStack.pop_back(); 1150b57cec5SDimitry Andric return true; 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 11881ad6265SDimitry Andric void DiagnosticsEngine::Reset(bool soft /*=false*/) { 1190b57cec5SDimitry Andric ErrorOccurred = false; 1200b57cec5SDimitry Andric UncompilableErrorOccurred = false; 1210b57cec5SDimitry Andric FatalErrorOccurred = false; 1220b57cec5SDimitry Andric UnrecoverableErrorOccurred = false; 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric NumWarnings = 0; 1250b57cec5SDimitry Andric NumErrors = 0; 1260b57cec5SDimitry Andric TrapNumErrorsOccurred = 0; 1270b57cec5SDimitry Andric TrapNumUnrecoverableErrorsOccurred = 0; 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric CurDiagID = std::numeric_limits<unsigned>::max(); 1300b57cec5SDimitry Andric LastDiagLevel = DiagnosticIDs::Ignored; 1310b57cec5SDimitry Andric DelayedDiagID = 0; 1320b57cec5SDimitry Andric 13381ad6265SDimitry Andric if (!soft) { 1340b57cec5SDimitry Andric // Clear state related to #pragma diagnostic. 1350b57cec5SDimitry Andric DiagStates.clear(); 1360b57cec5SDimitry Andric DiagStatesByLoc.clear(); 1370b57cec5SDimitry Andric DiagStateOnPushStack.clear(); 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric // Create a DiagState and DiagStatePoint representing diagnostic changes 1400b57cec5SDimitry Andric // through command-line. 1410b57cec5SDimitry Andric DiagStates.emplace_back(); 1420b57cec5SDimitry Andric DiagStatesByLoc.appendFirst(&DiagStates.back()); 1430b57cec5SDimitry Andric } 14481ad6265SDimitry Andric } 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1, 147480093f4SDimitry Andric StringRef Arg2, StringRef Arg3) { 1480b57cec5SDimitry Andric if (DelayedDiagID) 1490b57cec5SDimitry Andric return; 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric DelayedDiagID = DiagID; 1520b57cec5SDimitry Andric DelayedDiagArg1 = Arg1.str(); 1530b57cec5SDimitry Andric DelayedDiagArg2 = Arg2.str(); 154480093f4SDimitry Andric DelayedDiagArg3 = Arg3.str(); 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric void DiagnosticsEngine::ReportDelayed() { 1580b57cec5SDimitry Andric unsigned ID = DelayedDiagID; 1590b57cec5SDimitry Andric DelayedDiagID = 0; 160480093f4SDimitry Andric Report(ID) << DelayedDiagArg1 << DelayedDiagArg2 << DelayedDiagArg3; 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric 16306c3fb27SDimitry Andric DiagnosticMapping & 16406c3fb27SDimitry Andric DiagnosticsEngine::DiagState::getOrAddMapping(diag::kind Diag) { 16506c3fb27SDimitry Andric std::pair<iterator, bool> Result = 16606c3fb27SDimitry Andric DiagMap.insert(std::make_pair(Diag, DiagnosticMapping())); 16706c3fb27SDimitry Andric 16806c3fb27SDimitry Andric // Initialize the entry if we added it. 16906c3fb27SDimitry Andric if (Result.second) 17006c3fb27SDimitry Andric Result.first->second = DiagnosticIDs::getDefaultMapping(Diag); 17106c3fb27SDimitry Andric 17206c3fb27SDimitry Andric return Result.first->second; 17306c3fb27SDimitry Andric } 17406c3fb27SDimitry Andric 1750b57cec5SDimitry Andric void DiagnosticsEngine::DiagStateMap::appendFirst(DiagState *State) { 1760b57cec5SDimitry Andric assert(Files.empty() && "not first"); 1770b57cec5SDimitry Andric FirstDiagState = CurDiagState = State; 1780b57cec5SDimitry Andric CurDiagStateLoc = SourceLocation(); 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric void DiagnosticsEngine::DiagStateMap::append(SourceManager &SrcMgr, 1820b57cec5SDimitry Andric SourceLocation Loc, 1830b57cec5SDimitry Andric DiagState *State) { 1840b57cec5SDimitry Andric CurDiagState = State; 1850b57cec5SDimitry Andric CurDiagStateLoc = Loc; 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedLoc(Loc); 1880b57cec5SDimitry Andric unsigned Offset = Decomp.second; 1890b57cec5SDimitry Andric for (File *F = getFile(SrcMgr, Decomp.first); F; 1900b57cec5SDimitry Andric Offset = F->ParentOffset, F = F->Parent) { 1910b57cec5SDimitry Andric F->HasLocalTransitions = true; 1920b57cec5SDimitry Andric auto &Last = F->StateTransitions.back(); 1930b57cec5SDimitry Andric assert(Last.Offset <= Offset && "state transitions added out of order"); 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric if (Last.Offset == Offset) { 1960b57cec5SDimitry Andric if (Last.State == State) 1970b57cec5SDimitry Andric break; 1980b57cec5SDimitry Andric Last.State = State; 1990b57cec5SDimitry Andric continue; 2000b57cec5SDimitry Andric } 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric F->StateTransitions.push_back({State, Offset}); 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric DiagnosticsEngine::DiagState * 2070b57cec5SDimitry Andric DiagnosticsEngine::DiagStateMap::lookup(SourceManager &SrcMgr, 2080b57cec5SDimitry Andric SourceLocation Loc) const { 2090b57cec5SDimitry Andric // Common case: we have not seen any diagnostic pragmas. 2100b57cec5SDimitry Andric if (Files.empty()) 2110b57cec5SDimitry Andric return FirstDiagState; 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedLoc(Loc); 2140b57cec5SDimitry Andric const File *F = getFile(SrcMgr, Decomp.first); 2150b57cec5SDimitry Andric return F->lookup(Decomp.second); 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric DiagnosticsEngine::DiagState * 2190b57cec5SDimitry Andric DiagnosticsEngine::DiagStateMap::File::lookup(unsigned Offset) const { 2200b57cec5SDimitry Andric auto OnePastIt = 2210b57cec5SDimitry Andric llvm::partition_point(StateTransitions, [=](const DiagStatePoint &P) { 2220b57cec5SDimitry Andric return P.Offset <= Offset; 2230b57cec5SDimitry Andric }); 2240b57cec5SDimitry Andric assert(OnePastIt != StateTransitions.begin() && "missing initial state"); 2250b57cec5SDimitry Andric return OnePastIt[-1].State; 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric DiagnosticsEngine::DiagStateMap::File * 2290b57cec5SDimitry Andric DiagnosticsEngine::DiagStateMap::getFile(SourceManager &SrcMgr, 2300b57cec5SDimitry Andric FileID ID) const { 2310b57cec5SDimitry Andric // Get or insert the File for this ID. 2320b57cec5SDimitry Andric auto Range = Files.equal_range(ID); 2330b57cec5SDimitry Andric if (Range.first != Range.second) 2340b57cec5SDimitry Andric return &Range.first->second; 2350b57cec5SDimitry Andric auto &F = Files.insert(Range.first, std::make_pair(ID, File()))->second; 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric // We created a new File; look up the diagnostic state at the start of it and 2380b57cec5SDimitry Andric // initialize it. 2390b57cec5SDimitry Andric if (ID.isValid()) { 2400b57cec5SDimitry Andric std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedIncludedLoc(ID); 2410b57cec5SDimitry Andric F.Parent = getFile(SrcMgr, Decomp.first); 2420b57cec5SDimitry Andric F.ParentOffset = Decomp.second; 2430b57cec5SDimitry Andric F.StateTransitions.push_back({F.Parent->lookup(Decomp.second), 0}); 2440b57cec5SDimitry Andric } else { 2450b57cec5SDimitry Andric // This is the (imaginary) root file into which we pretend all top-level 2460b57cec5SDimitry Andric // files are included; it descends from the initial state. 2470b57cec5SDimitry Andric // 2480b57cec5SDimitry Andric // FIXME: This doesn't guarantee that we use the same ordering as 2490b57cec5SDimitry Andric // isBeforeInTranslationUnit in the cases where someone invented another 2500b57cec5SDimitry Andric // top-level file and added diagnostic pragmas to it. See the code at the 2510b57cec5SDimitry Andric // end of isBeforeInTranslationUnit for the quirks it deals with. 2520b57cec5SDimitry Andric F.StateTransitions.push_back({FirstDiagState, 0}); 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric return &F; 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric void DiagnosticsEngine::DiagStateMap::dump(SourceManager &SrcMgr, 2580b57cec5SDimitry Andric StringRef DiagName) const { 2590b57cec5SDimitry Andric llvm::errs() << "diagnostic state at "; 2600b57cec5SDimitry Andric CurDiagStateLoc.print(llvm::errs(), SrcMgr); 2610b57cec5SDimitry Andric llvm::errs() << ": " << CurDiagState << "\n"; 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric for (auto &F : Files) { 2640b57cec5SDimitry Andric FileID ID = F.first; 2650b57cec5SDimitry Andric File &File = F.second; 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric bool PrintedOuterHeading = false; 2680b57cec5SDimitry Andric auto PrintOuterHeading = [&] { 2690b57cec5SDimitry Andric if (PrintedOuterHeading) return; 2700b57cec5SDimitry Andric PrintedOuterHeading = true; 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric llvm::errs() << "File " << &File << " <FileID " << ID.getHashValue() 273e8d8bef9SDimitry Andric << ">: " << SrcMgr.getBufferOrFake(ID).getBufferIdentifier(); 274e8d8bef9SDimitry Andric 2750b57cec5SDimitry Andric if (F.second.Parent) { 2760b57cec5SDimitry Andric std::pair<FileID, unsigned> Decomp = 2770b57cec5SDimitry Andric SrcMgr.getDecomposedIncludedLoc(ID); 2780b57cec5SDimitry Andric assert(File.ParentOffset == Decomp.second); 2790b57cec5SDimitry Andric llvm::errs() << " parent " << File.Parent << " <FileID " 2800b57cec5SDimitry Andric << Decomp.first.getHashValue() << "> "; 2810b57cec5SDimitry Andric SrcMgr.getLocForStartOfFile(Decomp.first) 2820b57cec5SDimitry Andric .getLocWithOffset(Decomp.second) 2830b57cec5SDimitry Andric .print(llvm::errs(), SrcMgr); 2840b57cec5SDimitry Andric } 2850b57cec5SDimitry Andric if (File.HasLocalTransitions) 2860b57cec5SDimitry Andric llvm::errs() << " has_local_transitions"; 2870b57cec5SDimitry Andric llvm::errs() << "\n"; 2880b57cec5SDimitry Andric }; 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric if (DiagName.empty()) 2910b57cec5SDimitry Andric PrintOuterHeading(); 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric for (DiagStatePoint &Transition : File.StateTransitions) { 2940b57cec5SDimitry Andric bool PrintedInnerHeading = false; 2950b57cec5SDimitry Andric auto PrintInnerHeading = [&] { 2960b57cec5SDimitry Andric if (PrintedInnerHeading) return; 2970b57cec5SDimitry Andric PrintedInnerHeading = true; 2980b57cec5SDimitry Andric 2990b57cec5SDimitry Andric PrintOuterHeading(); 3000b57cec5SDimitry Andric llvm::errs() << " "; 3010b57cec5SDimitry Andric SrcMgr.getLocForStartOfFile(ID) 3020b57cec5SDimitry Andric .getLocWithOffset(Transition.Offset) 3030b57cec5SDimitry Andric .print(llvm::errs(), SrcMgr); 3040b57cec5SDimitry Andric llvm::errs() << ": state " << Transition.State << ":\n"; 3050b57cec5SDimitry Andric }; 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric if (DiagName.empty()) 3080b57cec5SDimitry Andric PrintInnerHeading(); 3090b57cec5SDimitry Andric 3100b57cec5SDimitry Andric for (auto &Mapping : *Transition.State) { 3110b57cec5SDimitry Andric StringRef Option = 3120b57cec5SDimitry Andric DiagnosticIDs::getWarningOptionForDiag(Mapping.first); 3130b57cec5SDimitry Andric if (!DiagName.empty() && DiagName != Option) 3140b57cec5SDimitry Andric continue; 3150b57cec5SDimitry Andric 3160b57cec5SDimitry Andric PrintInnerHeading(); 3170b57cec5SDimitry Andric llvm::errs() << " "; 3180b57cec5SDimitry Andric if (Option.empty()) 3190b57cec5SDimitry Andric llvm::errs() << "<unknown " << Mapping.first << ">"; 3200b57cec5SDimitry Andric else 3210b57cec5SDimitry Andric llvm::errs() << Option; 3220b57cec5SDimitry Andric llvm::errs() << ": "; 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric switch (Mapping.second.getSeverity()) { 3250b57cec5SDimitry Andric case diag::Severity::Ignored: llvm::errs() << "ignored"; break; 3260b57cec5SDimitry Andric case diag::Severity::Remark: llvm::errs() << "remark"; break; 3270b57cec5SDimitry Andric case diag::Severity::Warning: llvm::errs() << "warning"; break; 3280b57cec5SDimitry Andric case diag::Severity::Error: llvm::errs() << "error"; break; 3290b57cec5SDimitry Andric case diag::Severity::Fatal: llvm::errs() << "fatal"; break; 3300b57cec5SDimitry Andric } 3310b57cec5SDimitry Andric 3320b57cec5SDimitry Andric if (!Mapping.second.isUser()) 3330b57cec5SDimitry Andric llvm::errs() << " default"; 3340b57cec5SDimitry Andric if (Mapping.second.isPragma()) 3350b57cec5SDimitry Andric llvm::errs() << " pragma"; 3360b57cec5SDimitry Andric if (Mapping.second.hasNoWarningAsError()) 3370b57cec5SDimitry Andric llvm::errs() << " no-error"; 3380b57cec5SDimitry Andric if (Mapping.second.hasNoErrorAsFatal()) 3390b57cec5SDimitry Andric llvm::errs() << " no-fatal"; 3400b57cec5SDimitry Andric if (Mapping.second.wasUpgradedFromWarning()) 3410b57cec5SDimitry Andric llvm::errs() << " overruled"; 3420b57cec5SDimitry Andric llvm::errs() << "\n"; 3430b57cec5SDimitry Andric } 3440b57cec5SDimitry Andric } 3450b57cec5SDimitry Andric } 3460b57cec5SDimitry Andric } 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric void DiagnosticsEngine::PushDiagStatePoint(DiagState *State, 3490b57cec5SDimitry Andric SourceLocation Loc) { 3500b57cec5SDimitry Andric assert(Loc.isValid() && "Adding invalid loc point"); 3510b57cec5SDimitry Andric DiagStatesByLoc.append(*SourceMgr, Loc, State); 3520b57cec5SDimitry Andric } 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map, 3550b57cec5SDimitry Andric SourceLocation L) { 3560b57cec5SDimitry Andric assert(Diag < diag::DIAG_UPPER_LIMIT && 3570b57cec5SDimitry Andric "Can only map builtin diagnostics"); 3580b57cec5SDimitry Andric assert((Diags->isBuiltinWarningOrExtension(Diag) || 3590b57cec5SDimitry Andric (Map == diag::Severity::Fatal || Map == diag::Severity::Error)) && 3600b57cec5SDimitry Andric "Cannot map errors into warnings!"); 3610b57cec5SDimitry Andric assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location"); 3620b57cec5SDimitry Andric 363*0fca6ea1SDimitry Andric // A command line -Wfoo has an invalid L and cannot override error/fatal 364*0fca6ea1SDimitry Andric // mapping, while a warning pragma can. 3650b57cec5SDimitry Andric bool WasUpgradedFromWarning = false; 366*0fca6ea1SDimitry Andric if (Map == diag::Severity::Warning && L.isInvalid()) { 3670b57cec5SDimitry Andric DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag); 3680b57cec5SDimitry Andric if (Info.getSeverity() == diag::Severity::Error || 3690b57cec5SDimitry Andric Info.getSeverity() == diag::Severity::Fatal) { 3700b57cec5SDimitry Andric Map = Info.getSeverity(); 3710b57cec5SDimitry Andric WasUpgradedFromWarning = true; 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric DiagnosticMapping Mapping = makeUserMapping(Map, L); 3750b57cec5SDimitry Andric Mapping.setUpgradedFromWarning(WasUpgradedFromWarning); 3760b57cec5SDimitry Andric 37704eeddc0SDimitry Andric // Make sure we propagate the NoWarningAsError flag from an existing 37804eeddc0SDimitry Andric // mapping (which may be the default mapping). 37904eeddc0SDimitry Andric DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag); 38004eeddc0SDimitry Andric Mapping.setNoWarningAsError(Info.hasNoWarningAsError() || 38104eeddc0SDimitry Andric Mapping.hasNoWarningAsError()); 38204eeddc0SDimitry Andric 3830b57cec5SDimitry Andric // Common case; setting all the diagnostics of a group in one place. 3840b57cec5SDimitry Andric if ((L.isInvalid() || L == DiagStatesByLoc.getCurDiagStateLoc()) && 3850b57cec5SDimitry Andric DiagStatesByLoc.getCurDiagState()) { 3860b57cec5SDimitry Andric // FIXME: This is theoretically wrong: if the current state is shared with 3870b57cec5SDimitry Andric // some other location (via push/pop) we will change the state for that 3880b57cec5SDimitry Andric // other location as well. This cannot currently happen, as we can't update 3890b57cec5SDimitry Andric // the diagnostic state at the same location at which we pop. 3900b57cec5SDimitry Andric DiagStatesByLoc.getCurDiagState()->setMapping(Diag, Mapping); 3910b57cec5SDimitry Andric return; 3920b57cec5SDimitry Andric } 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric // A diagnostic pragma occurred, create a new DiagState initialized with 3950b57cec5SDimitry Andric // the current one and a new DiagStatePoint to record at which location 3960b57cec5SDimitry Andric // the new state became active. 3970b57cec5SDimitry Andric DiagStates.push_back(*GetCurDiagState()); 3980b57cec5SDimitry Andric DiagStates.back().setMapping(Diag, Mapping); 3990b57cec5SDimitry Andric PushDiagStatePoint(&DiagStates.back(), L); 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor, 4030b57cec5SDimitry Andric StringRef Group, diag::Severity Map, 4040b57cec5SDimitry Andric SourceLocation Loc) { 4050b57cec5SDimitry Andric // Get the diagnostics in this group. 4060b57cec5SDimitry Andric SmallVector<diag::kind, 256> GroupDiags; 4070b57cec5SDimitry Andric if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags)) 4080b57cec5SDimitry Andric return true; 4090b57cec5SDimitry Andric 4100b57cec5SDimitry Andric // Set the mapping. 4110b57cec5SDimitry Andric for (diag::kind Diag : GroupDiags) 4120b57cec5SDimitry Andric setSeverity(Diag, Map, Loc); 4130b57cec5SDimitry Andric 4140b57cec5SDimitry Andric return false; 4150b57cec5SDimitry Andric } 4160b57cec5SDimitry Andric 417349cc55cSDimitry Andric bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor, 418349cc55cSDimitry Andric diag::Group Group, 419349cc55cSDimitry Andric diag::Severity Map, 420349cc55cSDimitry Andric SourceLocation Loc) { 421349cc55cSDimitry Andric return setSeverityForGroup(Flavor, Diags->getWarningOptionForGroup(Group), 422349cc55cSDimitry Andric Map, Loc); 423349cc55cSDimitry Andric } 424349cc55cSDimitry Andric 4250b57cec5SDimitry Andric bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group, 4260b57cec5SDimitry Andric bool Enabled) { 4270b57cec5SDimitry Andric // If we are enabling this feature, just set the diagnostic mappings to map to 4280b57cec5SDimitry Andric // errors. 4290b57cec5SDimitry Andric if (Enabled) 4300b57cec5SDimitry Andric return setSeverityForGroup(diag::Flavor::WarningOrError, Group, 4310b57cec5SDimitry Andric diag::Severity::Error); 4320b57cec5SDimitry Andric 4330b57cec5SDimitry Andric // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and 4340b57cec5SDimitry Andric // potentially downgrade anything already mapped to be a warning. 4350b57cec5SDimitry Andric 4360b57cec5SDimitry Andric // Get the diagnostics in this group. 4370b57cec5SDimitry Andric SmallVector<diag::kind, 8> GroupDiags; 4380b57cec5SDimitry Andric if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group, 4390b57cec5SDimitry Andric GroupDiags)) 4400b57cec5SDimitry Andric return true; 4410b57cec5SDimitry Andric 4420b57cec5SDimitry Andric // Perform the mapping change. 4430b57cec5SDimitry Andric for (diag::kind Diag : GroupDiags) { 4440b57cec5SDimitry Andric DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag); 4450b57cec5SDimitry Andric 4460b57cec5SDimitry Andric if (Info.getSeverity() == diag::Severity::Error || 4470b57cec5SDimitry Andric Info.getSeverity() == diag::Severity::Fatal) 4480b57cec5SDimitry Andric Info.setSeverity(diag::Severity::Warning); 4490b57cec5SDimitry Andric 4500b57cec5SDimitry Andric Info.setNoWarningAsError(true); 4510b57cec5SDimitry Andric } 4520b57cec5SDimitry Andric 4530b57cec5SDimitry Andric return false; 4540b57cec5SDimitry Andric } 4550b57cec5SDimitry Andric 4560b57cec5SDimitry Andric bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group, 4570b57cec5SDimitry Andric bool Enabled) { 4580b57cec5SDimitry Andric // If we are enabling this feature, just set the diagnostic mappings to map to 4590b57cec5SDimitry Andric // fatal errors. 4600b57cec5SDimitry Andric if (Enabled) 4610b57cec5SDimitry Andric return setSeverityForGroup(diag::Flavor::WarningOrError, Group, 4620b57cec5SDimitry Andric diag::Severity::Fatal); 4630b57cec5SDimitry Andric 4640b57cec5SDimitry Andric // Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit, 4650b57cec5SDimitry Andric // and potentially downgrade anything already mapped to be a fatal error. 4660b57cec5SDimitry Andric 4670b57cec5SDimitry Andric // Get the diagnostics in this group. 4680b57cec5SDimitry Andric SmallVector<diag::kind, 8> GroupDiags; 4690b57cec5SDimitry Andric if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group, 4700b57cec5SDimitry Andric GroupDiags)) 4710b57cec5SDimitry Andric return true; 4720b57cec5SDimitry Andric 4730b57cec5SDimitry Andric // Perform the mapping change. 4740b57cec5SDimitry Andric for (diag::kind Diag : GroupDiags) { 4750b57cec5SDimitry Andric DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag); 4760b57cec5SDimitry Andric 4770b57cec5SDimitry Andric if (Info.getSeverity() == diag::Severity::Fatal) 4780b57cec5SDimitry Andric Info.setSeverity(diag::Severity::Error); 4790b57cec5SDimitry Andric 4800b57cec5SDimitry Andric Info.setNoErrorAsFatal(true); 4810b57cec5SDimitry Andric } 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric return false; 4840b57cec5SDimitry Andric } 4850b57cec5SDimitry Andric 4860b57cec5SDimitry Andric void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor, 4870b57cec5SDimitry Andric diag::Severity Map, 4880b57cec5SDimitry Andric SourceLocation Loc) { 4890b57cec5SDimitry Andric // Get all the diagnostics. 4900b57cec5SDimitry Andric std::vector<diag::kind> AllDiags; 4910b57cec5SDimitry Andric DiagnosticIDs::getAllDiagnostics(Flavor, AllDiags); 4920b57cec5SDimitry Andric 4930b57cec5SDimitry Andric // Set the mapping. 4940b57cec5SDimitry Andric for (diag::kind Diag : AllDiags) 4950b57cec5SDimitry Andric if (Diags->isBuiltinWarningOrExtension(Diag)) 4960b57cec5SDimitry Andric setSeverity(Diag, Map, Loc); 4970b57cec5SDimitry Andric } 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) { 5000b57cec5SDimitry Andric assert(CurDiagID == std::numeric_limits<unsigned>::max() && 5010b57cec5SDimitry Andric "Multiple diagnostics in flight at once!"); 5020b57cec5SDimitry Andric 5030b57cec5SDimitry Andric CurDiagLoc = storedDiag.getLocation(); 5040b57cec5SDimitry Andric CurDiagID = storedDiag.getID(); 505e8d8bef9SDimitry Andric DiagStorage.NumDiagArgs = 0; 5060b57cec5SDimitry Andric 507e8d8bef9SDimitry Andric DiagStorage.DiagRanges.clear(); 508e8d8bef9SDimitry Andric DiagStorage.DiagRanges.append(storedDiag.range_begin(), 509e8d8bef9SDimitry Andric storedDiag.range_end()); 5100b57cec5SDimitry Andric 511e8d8bef9SDimitry Andric DiagStorage.FixItHints.clear(); 512e8d8bef9SDimitry Andric DiagStorage.FixItHints.append(storedDiag.fixit_begin(), 513e8d8bef9SDimitry Andric storedDiag.fixit_end()); 5140b57cec5SDimitry Andric 5150b57cec5SDimitry Andric assert(Client && "DiagnosticConsumer not set!"); 5160b57cec5SDimitry Andric Level DiagLevel = storedDiag.getLevel(); 5170b57cec5SDimitry Andric Diagnostic Info(this, storedDiag.getMessage()); 5180b57cec5SDimitry Andric Client->HandleDiagnostic(DiagLevel, Info); 5190b57cec5SDimitry Andric if (Client->IncludeInDiagnosticCounts()) { 5200b57cec5SDimitry Andric if (DiagLevel == DiagnosticsEngine::Warning) 5210b57cec5SDimitry Andric ++NumWarnings; 5220b57cec5SDimitry Andric } 5230b57cec5SDimitry Andric 5240b57cec5SDimitry Andric CurDiagID = std::numeric_limits<unsigned>::max(); 5250b57cec5SDimitry Andric } 5260b57cec5SDimitry Andric 5270b57cec5SDimitry Andric bool DiagnosticsEngine::EmitCurrentDiagnostic(bool Force) { 5280b57cec5SDimitry Andric assert(getClient() && "DiagnosticClient not set!"); 5290b57cec5SDimitry Andric 5300b57cec5SDimitry Andric bool Emitted; 5310b57cec5SDimitry Andric if (Force) { 5320b57cec5SDimitry Andric Diagnostic Info(this); 5330b57cec5SDimitry Andric 5340b57cec5SDimitry Andric // Figure out the diagnostic level of this message. 5350b57cec5SDimitry Andric DiagnosticIDs::Level DiagLevel 5360b57cec5SDimitry Andric = Diags->getDiagnosticLevel(Info.getID(), Info.getLocation(), *this); 5370b57cec5SDimitry Andric 5380b57cec5SDimitry Andric Emitted = (DiagLevel != DiagnosticIDs::Ignored); 5390b57cec5SDimitry Andric if (Emitted) { 5400b57cec5SDimitry Andric // Emit the diagnostic regardless of suppression level. 5410b57cec5SDimitry Andric Diags->EmitDiag(*this, DiagLevel); 5420b57cec5SDimitry Andric } 5430b57cec5SDimitry Andric } else { 5440b57cec5SDimitry Andric // Process the diagnostic, sending the accumulated information to the 5450b57cec5SDimitry Andric // DiagnosticConsumer. 5460b57cec5SDimitry Andric Emitted = ProcessDiag(); 5470b57cec5SDimitry Andric } 5480b57cec5SDimitry Andric 5490b57cec5SDimitry Andric // Clear out the current diagnostic object. 5500b57cec5SDimitry Andric Clear(); 5510b57cec5SDimitry Andric 5520b57cec5SDimitry Andric // If there was a delayed diagnostic, emit it now. 5530b57cec5SDimitry Andric if (!Force && DelayedDiagID) 5540b57cec5SDimitry Andric ReportDelayed(); 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric return Emitted; 5570b57cec5SDimitry Andric } 5580b57cec5SDimitry Andric 5590b57cec5SDimitry Andric DiagnosticConsumer::~DiagnosticConsumer() = default; 5600b57cec5SDimitry Andric 5610b57cec5SDimitry Andric void DiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 5620b57cec5SDimitry Andric const Diagnostic &Info) { 5630b57cec5SDimitry Andric if (!IncludeInDiagnosticCounts()) 5640b57cec5SDimitry Andric return; 5650b57cec5SDimitry Andric 5660b57cec5SDimitry Andric if (DiagLevel == DiagnosticsEngine::Warning) 5670b57cec5SDimitry Andric ++NumWarnings; 5680b57cec5SDimitry Andric else if (DiagLevel >= DiagnosticsEngine::Error) 5690b57cec5SDimitry Andric ++NumErrors; 5700b57cec5SDimitry Andric } 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric /// ModifierIs - Return true if the specified modifier matches specified string. 5730b57cec5SDimitry Andric template <std::size_t StrLen> 5740b57cec5SDimitry Andric static bool ModifierIs(const char *Modifier, unsigned ModifierLen, 5750b57cec5SDimitry Andric const char (&Str)[StrLen]) { 5760b57cec5SDimitry Andric return StrLen-1 == ModifierLen && memcmp(Modifier, Str, StrLen-1) == 0; 5770b57cec5SDimitry Andric } 5780b57cec5SDimitry Andric 5790b57cec5SDimitry Andric /// ScanForward - Scans forward, looking for the given character, skipping 5800b57cec5SDimitry Andric /// nested clauses and escaped characters. 5810b57cec5SDimitry Andric static const char *ScanFormat(const char *I, const char *E, char Target) { 5820b57cec5SDimitry Andric unsigned Depth = 0; 5830b57cec5SDimitry Andric 5840b57cec5SDimitry Andric for ( ; I != E; ++I) { 5850b57cec5SDimitry Andric if (Depth == 0 && *I == Target) return I; 5860b57cec5SDimitry Andric if (Depth != 0 && *I == '}') Depth--; 5870b57cec5SDimitry Andric 5880b57cec5SDimitry Andric if (*I == '%') { 5890b57cec5SDimitry Andric I++; 5900b57cec5SDimitry Andric if (I == E) break; 5910b57cec5SDimitry Andric 5920b57cec5SDimitry Andric // Escaped characters get implicitly skipped here. 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric // Format specifier. 5950b57cec5SDimitry Andric if (!isDigit(*I) && !isPunctuation(*I)) { 5960b57cec5SDimitry Andric for (I++; I != E && !isDigit(*I) && *I != '{'; I++) ; 5970b57cec5SDimitry Andric if (I == E) break; 5980b57cec5SDimitry Andric if (*I == '{') 5990b57cec5SDimitry Andric Depth++; 6000b57cec5SDimitry Andric } 6010b57cec5SDimitry Andric } 6020b57cec5SDimitry Andric } 6030b57cec5SDimitry Andric return E; 6040b57cec5SDimitry Andric } 6050b57cec5SDimitry Andric 6060b57cec5SDimitry Andric /// HandleSelectModifier - Handle the integer 'select' modifier. This is used 6070b57cec5SDimitry Andric /// like this: %select{foo|bar|baz}2. This means that the integer argument 6080b57cec5SDimitry Andric /// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'. 6090b57cec5SDimitry Andric /// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'. 6100b57cec5SDimitry Andric /// This is very useful for certain classes of variant diagnostics. 6110b57cec5SDimitry Andric static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo, 6120b57cec5SDimitry Andric const char *Argument, unsigned ArgumentLen, 6130b57cec5SDimitry Andric SmallVectorImpl<char> &OutStr) { 6140b57cec5SDimitry Andric const char *ArgumentEnd = Argument+ArgumentLen; 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric // Skip over 'ValNo' |'s. 6170b57cec5SDimitry Andric while (ValNo) { 6180b57cec5SDimitry Andric const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|'); 6190b57cec5SDimitry Andric assert(NextVal != ArgumentEnd && "Value for integer select modifier was" 6200b57cec5SDimitry Andric " larger than the number of options in the diagnostic string!"); 6210b57cec5SDimitry Andric Argument = NextVal+1; // Skip this string. 6220b57cec5SDimitry Andric --ValNo; 6230b57cec5SDimitry Andric } 6240b57cec5SDimitry Andric 6250b57cec5SDimitry Andric // Get the end of the value. This is either the } or the |. 6260b57cec5SDimitry Andric const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|'); 6270b57cec5SDimitry Andric 6280b57cec5SDimitry Andric // Recursively format the result of the select clause into the output string. 6290b57cec5SDimitry Andric DInfo.FormatDiagnostic(Argument, EndPtr, OutStr); 6300b57cec5SDimitry Andric } 6310b57cec5SDimitry Andric 6320b57cec5SDimitry Andric /// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the 6330b57cec5SDimitry Andric /// letter 's' to the string if the value is not 1. This is used in cases like 6340b57cec5SDimitry Andric /// this: "you idiot, you have %4 parameter%s4!". 6350b57cec5SDimitry Andric static void HandleIntegerSModifier(unsigned ValNo, 6360b57cec5SDimitry Andric SmallVectorImpl<char> &OutStr) { 6370b57cec5SDimitry Andric if (ValNo != 1) 6380b57cec5SDimitry Andric OutStr.push_back('s'); 6390b57cec5SDimitry Andric } 6400b57cec5SDimitry Andric 6410b57cec5SDimitry Andric /// HandleOrdinalModifier - Handle the integer 'ord' modifier. This 6420b57cec5SDimitry Andric /// prints the ordinal form of the given integer, with 1 corresponding 6430b57cec5SDimitry Andric /// to the first ordinal. Currently this is hard-coded to use the 6440b57cec5SDimitry Andric /// English form. 6450b57cec5SDimitry Andric static void HandleOrdinalModifier(unsigned ValNo, 6460b57cec5SDimitry Andric SmallVectorImpl<char> &OutStr) { 6470b57cec5SDimitry Andric assert(ValNo != 0 && "ValNo must be strictly positive!"); 6480b57cec5SDimitry Andric 6490b57cec5SDimitry Andric llvm::raw_svector_ostream Out(OutStr); 6500b57cec5SDimitry Andric 6510b57cec5SDimitry Andric // We could use text forms for the first N ordinals, but the numeric 6520b57cec5SDimitry Andric // forms are actually nicer in diagnostics because they stand out. 6530b57cec5SDimitry Andric Out << ValNo << llvm::getOrdinalSuffix(ValNo); 6540b57cec5SDimitry Andric } 6550b57cec5SDimitry Andric 6560b57cec5SDimitry Andric /// PluralNumber - Parse an unsigned integer and advance Start. 6570b57cec5SDimitry Andric static unsigned PluralNumber(const char *&Start, const char *End) { 6580b57cec5SDimitry Andric // Programming 101: Parse a decimal number :-) 6590b57cec5SDimitry Andric unsigned Val = 0; 6600b57cec5SDimitry Andric while (Start != End && *Start >= '0' && *Start <= '9') { 6610b57cec5SDimitry Andric Val *= 10; 6620b57cec5SDimitry Andric Val += *Start - '0'; 6630b57cec5SDimitry Andric ++Start; 6640b57cec5SDimitry Andric } 6650b57cec5SDimitry Andric return Val; 6660b57cec5SDimitry Andric } 6670b57cec5SDimitry Andric 6680b57cec5SDimitry Andric /// TestPluralRange - Test if Val is in the parsed range. Modifies Start. 6690b57cec5SDimitry Andric static bool TestPluralRange(unsigned Val, const char *&Start, const char *End) { 6700b57cec5SDimitry Andric if (*Start != '[') { 6710b57cec5SDimitry Andric unsigned Ref = PluralNumber(Start, End); 6720b57cec5SDimitry Andric return Ref == Val; 6730b57cec5SDimitry Andric } 6740b57cec5SDimitry Andric 6750b57cec5SDimitry Andric ++Start; 6760b57cec5SDimitry Andric unsigned Low = PluralNumber(Start, End); 6770b57cec5SDimitry Andric assert(*Start == ',' && "Bad plural expression syntax: expected ,"); 6780b57cec5SDimitry Andric ++Start; 6790b57cec5SDimitry Andric unsigned High = PluralNumber(Start, End); 6800b57cec5SDimitry Andric assert(*Start == ']' && "Bad plural expression syntax: expected )"); 6810b57cec5SDimitry Andric ++Start; 6820b57cec5SDimitry Andric return Low <= Val && Val <= High; 6830b57cec5SDimitry Andric } 6840b57cec5SDimitry Andric 6850b57cec5SDimitry Andric /// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier. 6860b57cec5SDimitry Andric static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) { 6870b57cec5SDimitry Andric // Empty condition? 6880b57cec5SDimitry Andric if (*Start == ':') 6890b57cec5SDimitry Andric return true; 6900b57cec5SDimitry Andric 6910b57cec5SDimitry Andric while (true) { 6920b57cec5SDimitry Andric char C = *Start; 6930b57cec5SDimitry Andric if (C == '%') { 6940b57cec5SDimitry Andric // Modulo expression 6950b57cec5SDimitry Andric ++Start; 6960b57cec5SDimitry Andric unsigned Arg = PluralNumber(Start, End); 6970b57cec5SDimitry Andric assert(*Start == '=' && "Bad plural expression syntax: expected ="); 6980b57cec5SDimitry Andric ++Start; 6990b57cec5SDimitry Andric unsigned ValMod = ValNo % Arg; 7000b57cec5SDimitry Andric if (TestPluralRange(ValMod, Start, End)) 7010b57cec5SDimitry Andric return true; 7020b57cec5SDimitry Andric } else { 7030b57cec5SDimitry Andric assert((C == '[' || (C >= '0' && C <= '9')) && 7040b57cec5SDimitry Andric "Bad plural expression syntax: unexpected character"); 7050b57cec5SDimitry Andric // Range expression 7060b57cec5SDimitry Andric if (TestPluralRange(ValNo, Start, End)) 7070b57cec5SDimitry Andric return true; 7080b57cec5SDimitry Andric } 7090b57cec5SDimitry Andric 7100b57cec5SDimitry Andric // Scan for next or-expr part. 7110b57cec5SDimitry Andric Start = std::find(Start, End, ','); 7120b57cec5SDimitry Andric if (Start == End) 7130b57cec5SDimitry Andric break; 7140b57cec5SDimitry Andric ++Start; 7150b57cec5SDimitry Andric } 7160b57cec5SDimitry Andric return false; 7170b57cec5SDimitry Andric } 7180b57cec5SDimitry Andric 7190b57cec5SDimitry Andric /// HandlePluralModifier - Handle the integer 'plural' modifier. This is used 7200b57cec5SDimitry Andric /// for complex plural forms, or in languages where all plurals are complex. 7210b57cec5SDimitry Andric /// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are 7220b57cec5SDimitry Andric /// conditions that are tested in order, the form corresponding to the first 7230b57cec5SDimitry Andric /// that applies being emitted. The empty condition is always true, making the 7240b57cec5SDimitry Andric /// last form a default case. 7250b57cec5SDimitry Andric /// Conditions are simple boolean expressions, where n is the number argument. 7260b57cec5SDimitry Andric /// Here are the rules. 7270b57cec5SDimitry Andric /// condition := expression | empty 7280b57cec5SDimitry Andric /// empty := -> always true 7290b57cec5SDimitry Andric /// expression := numeric [',' expression] -> logical or 7300b57cec5SDimitry Andric /// numeric := range -> true if n in range 7310b57cec5SDimitry Andric /// | '%' number '=' range -> true if n % number in range 7320b57cec5SDimitry Andric /// range := number 7330b57cec5SDimitry Andric /// | '[' number ',' number ']' -> ranges are inclusive both ends 7340b57cec5SDimitry Andric /// 7350b57cec5SDimitry Andric /// Here are some examples from the GNU gettext manual written in this form: 7360b57cec5SDimitry Andric /// English: 7370b57cec5SDimitry Andric /// {1:form0|:form1} 7380b57cec5SDimitry Andric /// Latvian: 7390b57cec5SDimitry Andric /// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0} 7400b57cec5SDimitry Andric /// Gaeilge: 7410b57cec5SDimitry Andric /// {1:form0|2:form1|:form2} 7420b57cec5SDimitry Andric /// Romanian: 7430b57cec5SDimitry Andric /// {1:form0|0,%100=[1,19]:form1|:form2} 7440b57cec5SDimitry Andric /// Lithuanian: 7450b57cec5SDimitry Andric /// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1} 7460b57cec5SDimitry Andric /// Russian (requires repeated form): 7470b57cec5SDimitry Andric /// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2} 7480b57cec5SDimitry Andric /// Slovak 7490b57cec5SDimitry Andric /// {1:form0|[2,4]:form1|:form2} 7500b57cec5SDimitry Andric /// Polish (requires repeated form): 7510b57cec5SDimitry Andric /// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2} 7520b57cec5SDimitry Andric static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo, 7530b57cec5SDimitry Andric const char *Argument, unsigned ArgumentLen, 7540b57cec5SDimitry Andric SmallVectorImpl<char> &OutStr) { 7550b57cec5SDimitry Andric const char *ArgumentEnd = Argument + ArgumentLen; 7560b57cec5SDimitry Andric while (true) { 7570b57cec5SDimitry Andric assert(Argument < ArgumentEnd && "Plural expression didn't match."); 7580b57cec5SDimitry Andric const char *ExprEnd = Argument; 7590b57cec5SDimitry Andric while (*ExprEnd != ':') { 7600b57cec5SDimitry Andric assert(ExprEnd != ArgumentEnd && "Plural missing expression end"); 7610b57cec5SDimitry Andric ++ExprEnd; 7620b57cec5SDimitry Andric } 7630b57cec5SDimitry Andric if (EvalPluralExpr(ValNo, Argument, ExprEnd)) { 7640b57cec5SDimitry Andric Argument = ExprEnd + 1; 7650b57cec5SDimitry Andric ExprEnd = ScanFormat(Argument, ArgumentEnd, '|'); 7660b57cec5SDimitry Andric 7670b57cec5SDimitry Andric // Recursively format the result of the plural clause into the 7680b57cec5SDimitry Andric // output string. 7690b57cec5SDimitry Andric DInfo.FormatDiagnostic(Argument, ExprEnd, OutStr); 7700b57cec5SDimitry Andric return; 7710b57cec5SDimitry Andric } 7720b57cec5SDimitry Andric Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1; 7730b57cec5SDimitry Andric } 7740b57cec5SDimitry Andric } 7750b57cec5SDimitry Andric 7760b57cec5SDimitry Andric /// Returns the friendly description for a token kind that will appear 7770b57cec5SDimitry Andric /// without quotes in diagnostic messages. These strings may be translatable in 7780b57cec5SDimitry Andric /// future. 7790b57cec5SDimitry Andric static const char *getTokenDescForDiagnostic(tok::TokenKind Kind) { 7800b57cec5SDimitry Andric switch (Kind) { 7810b57cec5SDimitry Andric case tok::identifier: 7820b57cec5SDimitry Andric return "identifier"; 7830b57cec5SDimitry Andric default: 7840b57cec5SDimitry Andric return nullptr; 7850b57cec5SDimitry Andric } 7860b57cec5SDimitry Andric } 7870b57cec5SDimitry Andric 7880b57cec5SDimitry Andric /// FormatDiagnostic - Format this diagnostic into a string, substituting the 7890b57cec5SDimitry Andric /// formal arguments into the %0 slots. The result is appended onto the Str 7900b57cec5SDimitry Andric /// array. 7910b57cec5SDimitry Andric void Diagnostic:: 7920b57cec5SDimitry Andric FormatDiagnostic(SmallVectorImpl<char> &OutStr) const { 79306c3fb27SDimitry Andric if (StoredDiagMessage.has_value()) { 79406c3fb27SDimitry Andric OutStr.append(StoredDiagMessage->begin(), StoredDiagMessage->end()); 7950b57cec5SDimitry Andric return; 7960b57cec5SDimitry Andric } 7970b57cec5SDimitry Andric 7980b57cec5SDimitry Andric StringRef Diag = 7990b57cec5SDimitry Andric getDiags()->getDiagnosticIDs()->getDescription(getID()); 8000b57cec5SDimitry Andric 8010b57cec5SDimitry Andric FormatDiagnostic(Diag.begin(), Diag.end(), OutStr); 8020b57cec5SDimitry Andric } 8030b57cec5SDimitry Andric 8045f757f3fSDimitry Andric /// EscapeStringForDiagnostic - Append Str to the diagnostic buffer, 80581ad6265SDimitry Andric /// escaping non-printable characters and ill-formed code unit sequences. 8065f757f3fSDimitry Andric void clang::EscapeStringForDiagnostic(StringRef Str, 8075f757f3fSDimitry Andric SmallVectorImpl<char> &OutStr) { 80881ad6265SDimitry Andric OutStr.reserve(OutStr.size() + Str.size()); 80981ad6265SDimitry Andric auto *Begin = reinterpret_cast<const unsigned char *>(Str.data()); 81081ad6265SDimitry Andric llvm::raw_svector_ostream OutStream(OutStr); 81181ad6265SDimitry Andric const unsigned char *End = Begin + Str.size(); 81281ad6265SDimitry Andric while (Begin != End) { 81381ad6265SDimitry Andric // ASCII case 81481ad6265SDimitry Andric if (isPrintable(*Begin) || isWhitespace(*Begin)) { 81581ad6265SDimitry Andric OutStream << *Begin; 81681ad6265SDimitry Andric ++Begin; 81781ad6265SDimitry Andric continue; 81881ad6265SDimitry Andric } 81981ad6265SDimitry Andric if (llvm::isLegalUTF8Sequence(Begin, End)) { 82081ad6265SDimitry Andric llvm::UTF32 CodepointValue; 82181ad6265SDimitry Andric llvm::UTF32 *CpPtr = &CodepointValue; 82281ad6265SDimitry Andric const unsigned char *CodepointBegin = Begin; 82381ad6265SDimitry Andric const unsigned char *CodepointEnd = 82481ad6265SDimitry Andric Begin + llvm::getNumBytesForUTF8(*Begin); 82581ad6265SDimitry Andric llvm::ConversionResult Res = llvm::ConvertUTF8toUTF32( 82681ad6265SDimitry Andric &Begin, CodepointEnd, &CpPtr, CpPtr + 1, llvm::strictConversion); 82781ad6265SDimitry Andric (void)Res; 82881ad6265SDimitry Andric assert( 82981ad6265SDimitry Andric llvm::conversionOK == Res && 83081ad6265SDimitry Andric "the sequence is legal UTF-8 but we couldn't convert it to UTF-32"); 83181ad6265SDimitry Andric assert(Begin == CodepointEnd && 83281ad6265SDimitry Andric "we must be further along in the string now"); 83381ad6265SDimitry Andric if (llvm::sys::unicode::isPrintable(CodepointValue) || 83481ad6265SDimitry Andric llvm::sys::unicode::isFormatting(CodepointValue)) { 83581ad6265SDimitry Andric OutStr.append(CodepointBegin, CodepointEnd); 83681ad6265SDimitry Andric continue; 83781ad6265SDimitry Andric } 83881ad6265SDimitry Andric // Unprintable code point. 83981ad6265SDimitry Andric OutStream << "<U+" << llvm::format_hex_no_prefix(CodepointValue, 4, true) 84081ad6265SDimitry Andric << ">"; 84181ad6265SDimitry Andric continue; 84281ad6265SDimitry Andric } 84381ad6265SDimitry Andric // Invalid code unit. 84481ad6265SDimitry Andric OutStream << "<" << llvm::format_hex_no_prefix(*Begin, 2, true) << ">"; 84581ad6265SDimitry Andric ++Begin; 84681ad6265SDimitry Andric } 84781ad6265SDimitry Andric } 84881ad6265SDimitry Andric 8490b57cec5SDimitry Andric void Diagnostic:: 8500b57cec5SDimitry Andric FormatDiagnostic(const char *DiagStr, const char *DiagEnd, 8510b57cec5SDimitry Andric SmallVectorImpl<char> &OutStr) const { 8520b57cec5SDimitry Andric // When the diagnostic string is only "%0", the entire string is being given 8530b57cec5SDimitry Andric // by an outside source. Remove unprintable characters from this string 8540b57cec5SDimitry Andric // and skip all the other string processing. 855*0fca6ea1SDimitry Andric if (DiagEnd - DiagStr == 2 && StringRef(DiagStr, DiagEnd - DiagStr) == "%0" && 8560b57cec5SDimitry Andric getArgKind(0) == DiagnosticsEngine::ak_std_string) { 8570b57cec5SDimitry Andric const std::string &S = getArgStdStr(0); 8585f757f3fSDimitry Andric EscapeStringForDiagnostic(S, OutStr); 8590b57cec5SDimitry Andric return; 8600b57cec5SDimitry Andric } 8610b57cec5SDimitry Andric 8620b57cec5SDimitry Andric /// FormattedArgs - Keep track of all of the arguments formatted by 8630b57cec5SDimitry Andric /// ConvertArgToString and pass them into subsequent calls to 8640b57cec5SDimitry Andric /// ConvertArgToString, allowing the implementation to avoid redundancies in 8650b57cec5SDimitry Andric /// obvious cases. 8660b57cec5SDimitry Andric SmallVector<DiagnosticsEngine::ArgumentValue, 8> FormattedArgs; 8670b57cec5SDimitry Andric 8680b57cec5SDimitry Andric /// QualTypeVals - Pass a vector of arrays so that QualType names can be 8690b57cec5SDimitry Andric /// compared to see if more information is needed to be printed. 8700b57cec5SDimitry Andric SmallVector<intptr_t, 2> QualTypeVals; 871e8d8bef9SDimitry Andric SmallString<64> Tree; 8720b57cec5SDimitry Andric 8730b57cec5SDimitry Andric for (unsigned i = 0, e = getNumArgs(); i < e; ++i) 8740b57cec5SDimitry Andric if (getArgKind(i) == DiagnosticsEngine::ak_qualtype) 8750b57cec5SDimitry Andric QualTypeVals.push_back(getRawArg(i)); 8760b57cec5SDimitry Andric 8770b57cec5SDimitry Andric while (DiagStr != DiagEnd) { 8780b57cec5SDimitry Andric if (DiagStr[0] != '%') { 8790b57cec5SDimitry Andric // Append non-%0 substrings to Str if we have one. 8800b57cec5SDimitry Andric const char *StrEnd = std::find(DiagStr, DiagEnd, '%'); 8810b57cec5SDimitry Andric OutStr.append(DiagStr, StrEnd); 8820b57cec5SDimitry Andric DiagStr = StrEnd; 8830b57cec5SDimitry Andric continue; 8840b57cec5SDimitry Andric } else if (isPunctuation(DiagStr[1])) { 8850b57cec5SDimitry Andric OutStr.push_back(DiagStr[1]); // %% -> %. 8860b57cec5SDimitry Andric DiagStr += 2; 8870b57cec5SDimitry Andric continue; 8880b57cec5SDimitry Andric } 8890b57cec5SDimitry Andric 8900b57cec5SDimitry Andric // Skip the %. 8910b57cec5SDimitry Andric ++DiagStr; 8920b57cec5SDimitry Andric 8930b57cec5SDimitry Andric // This must be a placeholder for a diagnostic argument. The format for a 8940b57cec5SDimitry Andric // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0". 8950b57cec5SDimitry Andric // The digit is a number from 0-9 indicating which argument this comes from. 8960b57cec5SDimitry Andric // The modifier is a string of digits from the set [-a-z]+, arguments is a 8970b57cec5SDimitry Andric // brace enclosed string. 8980b57cec5SDimitry Andric const char *Modifier = nullptr, *Argument = nullptr; 8990b57cec5SDimitry Andric unsigned ModifierLen = 0, ArgumentLen = 0; 9000b57cec5SDimitry Andric 9010b57cec5SDimitry Andric // Check to see if we have a modifier. If so eat it. 9020b57cec5SDimitry Andric if (!isDigit(DiagStr[0])) { 9030b57cec5SDimitry Andric Modifier = DiagStr; 9040b57cec5SDimitry Andric while (DiagStr[0] == '-' || 9050b57cec5SDimitry Andric (DiagStr[0] >= 'a' && DiagStr[0] <= 'z')) 9060b57cec5SDimitry Andric ++DiagStr; 9070b57cec5SDimitry Andric ModifierLen = DiagStr-Modifier; 9080b57cec5SDimitry Andric 9090b57cec5SDimitry Andric // If we have an argument, get it next. 9100b57cec5SDimitry Andric if (DiagStr[0] == '{') { 9110b57cec5SDimitry Andric ++DiagStr; // Skip {. 9120b57cec5SDimitry Andric Argument = DiagStr; 9130b57cec5SDimitry Andric 9140b57cec5SDimitry Andric DiagStr = ScanFormat(DiagStr, DiagEnd, '}'); 9150b57cec5SDimitry Andric assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!"); 9160b57cec5SDimitry Andric ArgumentLen = DiagStr-Argument; 9170b57cec5SDimitry Andric ++DiagStr; // Skip }. 9180b57cec5SDimitry Andric } 9190b57cec5SDimitry Andric } 9200b57cec5SDimitry Andric 9210b57cec5SDimitry Andric assert(isDigit(*DiagStr) && "Invalid format for argument in diagnostic"); 9220b57cec5SDimitry Andric unsigned ArgNo = *DiagStr++ - '0'; 9230b57cec5SDimitry Andric 9240b57cec5SDimitry Andric // Only used for type diffing. 9250b57cec5SDimitry Andric unsigned ArgNo2 = ArgNo; 9260b57cec5SDimitry Andric 9270b57cec5SDimitry Andric DiagnosticsEngine::ArgumentKind Kind = getArgKind(ArgNo); 9280b57cec5SDimitry Andric if (ModifierIs(Modifier, ModifierLen, "diff")) { 9290b57cec5SDimitry Andric assert(*DiagStr == ',' && isDigit(*(DiagStr + 1)) && 9300b57cec5SDimitry Andric "Invalid format for diff modifier"); 9310b57cec5SDimitry Andric ++DiagStr; // Comma. 9320b57cec5SDimitry Andric ArgNo2 = *DiagStr++ - '0'; 9330b57cec5SDimitry Andric DiagnosticsEngine::ArgumentKind Kind2 = getArgKind(ArgNo2); 9340b57cec5SDimitry Andric if (Kind == DiagnosticsEngine::ak_qualtype && 9350b57cec5SDimitry Andric Kind2 == DiagnosticsEngine::ak_qualtype) 9360b57cec5SDimitry Andric Kind = DiagnosticsEngine::ak_qualtype_pair; 9370b57cec5SDimitry Andric else { 9380b57cec5SDimitry Andric // %diff only supports QualTypes. For other kinds of arguments, 9390b57cec5SDimitry Andric // use the default printing. For example, if the modifier is: 9400b57cec5SDimitry Andric // "%diff{compare $ to $|other text}1,2" 9410b57cec5SDimitry Andric // treat it as: 9420b57cec5SDimitry Andric // "compare %1 to %2" 9430b57cec5SDimitry Andric const char *ArgumentEnd = Argument + ArgumentLen; 9440b57cec5SDimitry Andric const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|'); 9450b57cec5SDimitry Andric assert(ScanFormat(Pipe + 1, ArgumentEnd, '|') == ArgumentEnd && 9460b57cec5SDimitry Andric "Found too many '|'s in a %diff modifier!"); 9470b57cec5SDimitry Andric const char *FirstDollar = ScanFormat(Argument, Pipe, '$'); 9480b57cec5SDimitry Andric const char *SecondDollar = ScanFormat(FirstDollar + 1, Pipe, '$'); 9490b57cec5SDimitry Andric const char ArgStr1[] = { '%', static_cast<char>('0' + ArgNo) }; 9500b57cec5SDimitry Andric const char ArgStr2[] = { '%', static_cast<char>('0' + ArgNo2) }; 9510b57cec5SDimitry Andric FormatDiagnostic(Argument, FirstDollar, OutStr); 9520b57cec5SDimitry Andric FormatDiagnostic(ArgStr1, ArgStr1 + 2, OutStr); 9530b57cec5SDimitry Andric FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr); 9540b57cec5SDimitry Andric FormatDiagnostic(ArgStr2, ArgStr2 + 2, OutStr); 9550b57cec5SDimitry Andric FormatDiagnostic(SecondDollar + 1, Pipe, OutStr); 9560b57cec5SDimitry Andric continue; 9570b57cec5SDimitry Andric } 9580b57cec5SDimitry Andric } 9590b57cec5SDimitry Andric 9600b57cec5SDimitry Andric switch (Kind) { 9610b57cec5SDimitry Andric // ---- STRINGS ---- 9620b57cec5SDimitry Andric case DiagnosticsEngine::ak_std_string: { 9630b57cec5SDimitry Andric const std::string &S = getArgStdStr(ArgNo); 9640b57cec5SDimitry Andric assert(ModifierLen == 0 && "No modifiers for strings yet"); 9655f757f3fSDimitry Andric EscapeStringForDiagnostic(S, OutStr); 9660b57cec5SDimitry Andric break; 9670b57cec5SDimitry Andric } 9680b57cec5SDimitry Andric case DiagnosticsEngine::ak_c_string: { 9690b57cec5SDimitry Andric const char *S = getArgCStr(ArgNo); 9700b57cec5SDimitry Andric assert(ModifierLen == 0 && "No modifiers for strings yet"); 9710b57cec5SDimitry Andric 9720b57cec5SDimitry Andric // Don't crash if get passed a null pointer by accident. 9730b57cec5SDimitry Andric if (!S) 9740b57cec5SDimitry Andric S = "(null)"; 9755f757f3fSDimitry Andric EscapeStringForDiagnostic(S, OutStr); 9760b57cec5SDimitry Andric break; 9770b57cec5SDimitry Andric } 9780b57cec5SDimitry Andric // ---- INTEGERS ---- 9790b57cec5SDimitry Andric case DiagnosticsEngine::ak_sint: { 980349cc55cSDimitry Andric int64_t Val = getArgSInt(ArgNo); 9810b57cec5SDimitry Andric 9820b57cec5SDimitry Andric if (ModifierIs(Modifier, ModifierLen, "select")) { 9830b57cec5SDimitry Andric HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen, 9840b57cec5SDimitry Andric OutStr); 9850b57cec5SDimitry Andric } else if (ModifierIs(Modifier, ModifierLen, "s")) { 9860b57cec5SDimitry Andric HandleIntegerSModifier(Val, OutStr); 9870b57cec5SDimitry Andric } else if (ModifierIs(Modifier, ModifierLen, "plural")) { 9880b57cec5SDimitry Andric HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen, 9890b57cec5SDimitry Andric OutStr); 9900b57cec5SDimitry Andric } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) { 9910b57cec5SDimitry Andric HandleOrdinalModifier((unsigned)Val, OutStr); 9920b57cec5SDimitry Andric } else { 9930b57cec5SDimitry Andric assert(ModifierLen == 0 && "Unknown integer modifier"); 9940b57cec5SDimitry Andric llvm::raw_svector_ostream(OutStr) << Val; 9950b57cec5SDimitry Andric } 9960b57cec5SDimitry Andric break; 9970b57cec5SDimitry Andric } 9980b57cec5SDimitry Andric case DiagnosticsEngine::ak_uint: { 999349cc55cSDimitry Andric uint64_t Val = getArgUInt(ArgNo); 10000b57cec5SDimitry Andric 10010b57cec5SDimitry Andric if (ModifierIs(Modifier, ModifierLen, "select")) { 10020b57cec5SDimitry Andric HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr); 10030b57cec5SDimitry Andric } else if (ModifierIs(Modifier, ModifierLen, "s")) { 10040b57cec5SDimitry Andric HandleIntegerSModifier(Val, OutStr); 10050b57cec5SDimitry Andric } else if (ModifierIs(Modifier, ModifierLen, "plural")) { 10060b57cec5SDimitry Andric HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen, 10070b57cec5SDimitry Andric OutStr); 10080b57cec5SDimitry Andric } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) { 10090b57cec5SDimitry Andric HandleOrdinalModifier(Val, OutStr); 10100b57cec5SDimitry Andric } else { 10110b57cec5SDimitry Andric assert(ModifierLen == 0 && "Unknown integer modifier"); 10120b57cec5SDimitry Andric llvm::raw_svector_ostream(OutStr) << Val; 10130b57cec5SDimitry Andric } 10140b57cec5SDimitry Andric break; 10150b57cec5SDimitry Andric } 10160b57cec5SDimitry Andric // ---- TOKEN SPELLINGS ---- 10170b57cec5SDimitry Andric case DiagnosticsEngine::ak_tokenkind: { 10180b57cec5SDimitry Andric tok::TokenKind Kind = static_cast<tok::TokenKind>(getRawArg(ArgNo)); 10190b57cec5SDimitry Andric assert(ModifierLen == 0 && "No modifiers for token kinds yet"); 10200b57cec5SDimitry Andric 10210b57cec5SDimitry Andric llvm::raw_svector_ostream Out(OutStr); 10220b57cec5SDimitry Andric if (const char *S = tok::getPunctuatorSpelling(Kind)) 10230b57cec5SDimitry Andric // Quoted token spelling for punctuators. 10240b57cec5SDimitry Andric Out << '\'' << S << '\''; 102581ad6265SDimitry Andric else if ((S = tok::getKeywordSpelling(Kind))) 10260b57cec5SDimitry Andric // Unquoted token spelling for keywords. 10270b57cec5SDimitry Andric Out << S; 102881ad6265SDimitry Andric else if ((S = getTokenDescForDiagnostic(Kind))) 10290b57cec5SDimitry Andric // Unquoted translatable token name. 10300b57cec5SDimitry Andric Out << S; 103181ad6265SDimitry Andric else if ((S = tok::getTokenName(Kind))) 10320b57cec5SDimitry Andric // Debug name, shouldn't appear in user-facing diagnostics. 10330b57cec5SDimitry Andric Out << '<' << S << '>'; 10340b57cec5SDimitry Andric else 10350b57cec5SDimitry Andric Out << "(null)"; 10360b57cec5SDimitry Andric break; 10370b57cec5SDimitry Andric } 10380b57cec5SDimitry Andric // ---- NAMES and TYPES ---- 10390b57cec5SDimitry Andric case DiagnosticsEngine::ak_identifierinfo: { 10400b57cec5SDimitry Andric const IdentifierInfo *II = getArgIdentifier(ArgNo); 10410b57cec5SDimitry Andric assert(ModifierLen == 0 && "No modifiers for strings yet"); 10420b57cec5SDimitry Andric 10430b57cec5SDimitry Andric // Don't crash if get passed a null pointer by accident. 10440b57cec5SDimitry Andric if (!II) { 10450b57cec5SDimitry Andric const char *S = "(null)"; 10460b57cec5SDimitry Andric OutStr.append(S, S + strlen(S)); 10470b57cec5SDimitry Andric continue; 10480b57cec5SDimitry Andric } 10490b57cec5SDimitry Andric 10500b57cec5SDimitry Andric llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\''; 10510b57cec5SDimitry Andric break; 10520b57cec5SDimitry Andric } 1053480093f4SDimitry Andric case DiagnosticsEngine::ak_addrspace: 10540b57cec5SDimitry Andric case DiagnosticsEngine::ak_qual: 10550b57cec5SDimitry Andric case DiagnosticsEngine::ak_qualtype: 10560b57cec5SDimitry Andric case DiagnosticsEngine::ak_declarationname: 10570b57cec5SDimitry Andric case DiagnosticsEngine::ak_nameddecl: 10580b57cec5SDimitry Andric case DiagnosticsEngine::ak_nestednamespec: 10590b57cec5SDimitry Andric case DiagnosticsEngine::ak_declcontext: 10600b57cec5SDimitry Andric case DiagnosticsEngine::ak_attr: 10610b57cec5SDimitry Andric getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo), 10620b57cec5SDimitry Andric StringRef(Modifier, ModifierLen), 10630b57cec5SDimitry Andric StringRef(Argument, ArgumentLen), 10640b57cec5SDimitry Andric FormattedArgs, 10650b57cec5SDimitry Andric OutStr, QualTypeVals); 10660b57cec5SDimitry Andric break; 10670b57cec5SDimitry Andric case DiagnosticsEngine::ak_qualtype_pair: { 10680b57cec5SDimitry Andric // Create a struct with all the info needed for printing. 10690b57cec5SDimitry Andric TemplateDiffTypes TDT; 10700b57cec5SDimitry Andric TDT.FromType = getRawArg(ArgNo); 10710b57cec5SDimitry Andric TDT.ToType = getRawArg(ArgNo2); 10720b57cec5SDimitry Andric TDT.ElideType = getDiags()->ElideType; 10730b57cec5SDimitry Andric TDT.ShowColors = getDiags()->ShowColors; 10740b57cec5SDimitry Andric TDT.TemplateDiffUsed = false; 10750b57cec5SDimitry Andric intptr_t val = reinterpret_cast<intptr_t>(&TDT); 10760b57cec5SDimitry Andric 10770b57cec5SDimitry Andric const char *ArgumentEnd = Argument + ArgumentLen; 10780b57cec5SDimitry Andric const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|'); 10790b57cec5SDimitry Andric 10800b57cec5SDimitry Andric // Print the tree. If this diagnostic already has a tree, skip the 10810b57cec5SDimitry Andric // second tree. 10820b57cec5SDimitry Andric if (getDiags()->PrintTemplateTree && Tree.empty()) { 10830b57cec5SDimitry Andric TDT.PrintFromType = true; 10840b57cec5SDimitry Andric TDT.PrintTree = true; 10850b57cec5SDimitry Andric getDiags()->ConvertArgToString(Kind, val, 10860b57cec5SDimitry Andric StringRef(Modifier, ModifierLen), 10870b57cec5SDimitry Andric StringRef(Argument, ArgumentLen), 10880b57cec5SDimitry Andric FormattedArgs, 10890b57cec5SDimitry Andric Tree, QualTypeVals); 10900b57cec5SDimitry Andric // If there is no tree information, fall back to regular printing. 10910b57cec5SDimitry Andric if (!Tree.empty()) { 10920b57cec5SDimitry Andric FormatDiagnostic(Pipe + 1, ArgumentEnd, OutStr); 10930b57cec5SDimitry Andric break; 10940b57cec5SDimitry Andric } 10950b57cec5SDimitry Andric } 10960b57cec5SDimitry Andric 10970b57cec5SDimitry Andric // Non-tree printing, also the fall-back when tree printing fails. 10980b57cec5SDimitry Andric // The fall-back is triggered when the types compared are not templates. 10990b57cec5SDimitry Andric const char *FirstDollar = ScanFormat(Argument, ArgumentEnd, '$'); 11000b57cec5SDimitry Andric const char *SecondDollar = ScanFormat(FirstDollar + 1, ArgumentEnd, '$'); 11010b57cec5SDimitry Andric 11020b57cec5SDimitry Andric // Append before text 11030b57cec5SDimitry Andric FormatDiagnostic(Argument, FirstDollar, OutStr); 11040b57cec5SDimitry Andric 11050b57cec5SDimitry Andric // Append first type 11060b57cec5SDimitry Andric TDT.PrintTree = false; 11070b57cec5SDimitry Andric TDT.PrintFromType = true; 11080b57cec5SDimitry Andric getDiags()->ConvertArgToString(Kind, val, 11090b57cec5SDimitry Andric StringRef(Modifier, ModifierLen), 11100b57cec5SDimitry Andric StringRef(Argument, ArgumentLen), 11110b57cec5SDimitry Andric FormattedArgs, 11120b57cec5SDimitry Andric OutStr, QualTypeVals); 11130b57cec5SDimitry Andric if (!TDT.TemplateDiffUsed) 11140b57cec5SDimitry Andric FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype, 11150b57cec5SDimitry Andric TDT.FromType)); 11160b57cec5SDimitry Andric 11170b57cec5SDimitry Andric // Append middle text 11180b57cec5SDimitry Andric FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr); 11190b57cec5SDimitry Andric 11200b57cec5SDimitry Andric // Append second type 11210b57cec5SDimitry Andric TDT.PrintFromType = false; 11220b57cec5SDimitry Andric getDiags()->ConvertArgToString(Kind, val, 11230b57cec5SDimitry Andric StringRef(Modifier, ModifierLen), 11240b57cec5SDimitry Andric StringRef(Argument, ArgumentLen), 11250b57cec5SDimitry Andric FormattedArgs, 11260b57cec5SDimitry Andric OutStr, QualTypeVals); 11270b57cec5SDimitry Andric if (!TDT.TemplateDiffUsed) 11280b57cec5SDimitry Andric FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype, 11290b57cec5SDimitry Andric TDT.ToType)); 11300b57cec5SDimitry Andric 11310b57cec5SDimitry Andric // Append end text 11320b57cec5SDimitry Andric FormatDiagnostic(SecondDollar + 1, Pipe, OutStr); 11330b57cec5SDimitry Andric break; 11340b57cec5SDimitry Andric } 11350b57cec5SDimitry Andric } 11360b57cec5SDimitry Andric 11370b57cec5SDimitry Andric // Remember this argument info for subsequent formatting operations. Turn 11380b57cec5SDimitry Andric // std::strings into a null terminated string to make it be the same case as 11390b57cec5SDimitry Andric // all the other ones. 11400b57cec5SDimitry Andric if (Kind == DiagnosticsEngine::ak_qualtype_pair) 11410b57cec5SDimitry Andric continue; 11420b57cec5SDimitry Andric else if (Kind != DiagnosticsEngine::ak_std_string) 11430b57cec5SDimitry Andric FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo))); 11440b57cec5SDimitry Andric else 11450b57cec5SDimitry Andric FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_c_string, 11460b57cec5SDimitry Andric (intptr_t)getArgStdStr(ArgNo).c_str())); 11470b57cec5SDimitry Andric } 11480b57cec5SDimitry Andric 11490b57cec5SDimitry Andric // Append the type tree to the end of the diagnostics. 11500b57cec5SDimitry Andric OutStr.append(Tree.begin(), Tree.end()); 11510b57cec5SDimitry Andric } 11520b57cec5SDimitry Andric 11530b57cec5SDimitry Andric StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, 11540b57cec5SDimitry Andric StringRef Message) 11550b57cec5SDimitry Andric : ID(ID), Level(Level), Message(Message) {} 11560b57cec5SDimitry Andric 11570b57cec5SDimitry Andric StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, 11580b57cec5SDimitry Andric const Diagnostic &Info) 11590b57cec5SDimitry Andric : ID(Info.getID()), Level(Level) { 11600b57cec5SDimitry Andric assert((Info.getLocation().isInvalid() || Info.hasSourceManager()) && 11610b57cec5SDimitry Andric "Valid source location without setting a source manager for diagnostic"); 11620b57cec5SDimitry Andric if (Info.getLocation().isValid()) 11630b57cec5SDimitry Andric Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager()); 11640b57cec5SDimitry Andric SmallString<64> Message; 11650b57cec5SDimitry Andric Info.FormatDiagnostic(Message); 11660b57cec5SDimitry Andric this->Message.assign(Message.begin(), Message.end()); 11670b57cec5SDimitry Andric this->Ranges.assign(Info.getRanges().begin(), Info.getRanges().end()); 11680b57cec5SDimitry Andric this->FixIts.assign(Info.getFixItHints().begin(), Info.getFixItHints().end()); 11690b57cec5SDimitry Andric } 11700b57cec5SDimitry Andric 11710b57cec5SDimitry Andric StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, 11720b57cec5SDimitry Andric StringRef Message, FullSourceLoc Loc, 11730b57cec5SDimitry Andric ArrayRef<CharSourceRange> Ranges, 11740b57cec5SDimitry Andric ArrayRef<FixItHint> FixIts) 11750b57cec5SDimitry Andric : ID(ID), Level(Level), Loc(Loc), Message(Message), 11760b57cec5SDimitry Andric Ranges(Ranges.begin(), Ranges.end()), FixIts(FixIts.begin(), FixIts.end()) 11770b57cec5SDimitry Andric { 11780b57cec5SDimitry Andric } 11790b57cec5SDimitry Andric 118081ad6265SDimitry Andric llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, 118181ad6265SDimitry Andric const StoredDiagnostic &SD) { 118281ad6265SDimitry Andric if (SD.getLocation().hasManager()) 118381ad6265SDimitry Andric OS << SD.getLocation().printToString(SD.getLocation().getManager()) << ": "; 118481ad6265SDimitry Andric OS << SD.getMessage(); 118581ad6265SDimitry Andric return OS; 118681ad6265SDimitry Andric } 118781ad6265SDimitry Andric 11880b57cec5SDimitry Andric /// IncludeInDiagnosticCounts - This method (whose default implementation 11890b57cec5SDimitry Andric /// returns true) indicates whether the diagnostics handled by this 11900b57cec5SDimitry Andric /// DiagnosticConsumer should be included in the number of diagnostics 11910b57cec5SDimitry Andric /// reported by DiagnosticsEngine. 11920b57cec5SDimitry Andric bool DiagnosticConsumer::IncludeInDiagnosticCounts() const { return true; } 11930b57cec5SDimitry Andric 11940b57cec5SDimitry Andric void IgnoringDiagConsumer::anchor() {} 11950b57cec5SDimitry Andric 11960b57cec5SDimitry Andric ForwardingDiagnosticConsumer::~ForwardingDiagnosticConsumer() = default; 11970b57cec5SDimitry Andric 11980b57cec5SDimitry Andric void ForwardingDiagnosticConsumer::HandleDiagnostic( 11990b57cec5SDimitry Andric DiagnosticsEngine::Level DiagLevel, 12000b57cec5SDimitry Andric const Diagnostic &Info) { 12010b57cec5SDimitry Andric Target.HandleDiagnostic(DiagLevel, Info); 12020b57cec5SDimitry Andric } 12030b57cec5SDimitry Andric 12040b57cec5SDimitry Andric void ForwardingDiagnosticConsumer::clear() { 12050b57cec5SDimitry Andric DiagnosticConsumer::clear(); 12060b57cec5SDimitry Andric Target.clear(); 12070b57cec5SDimitry Andric } 12080b57cec5SDimitry Andric 12090b57cec5SDimitry Andric bool ForwardingDiagnosticConsumer::IncludeInDiagnosticCounts() const { 12100b57cec5SDimitry Andric return Target.IncludeInDiagnosticCounts(); 12110b57cec5SDimitry Andric } 12120b57cec5SDimitry Andric 1213e8d8bef9SDimitry Andric PartialDiagnostic::DiagStorageAllocator::DiagStorageAllocator() { 12140b57cec5SDimitry Andric for (unsigned I = 0; I != NumCached; ++I) 12150b57cec5SDimitry Andric FreeList[I] = Cached + I; 12160b57cec5SDimitry Andric NumFreeListEntries = NumCached; 12170b57cec5SDimitry Andric } 12180b57cec5SDimitry Andric 1219e8d8bef9SDimitry Andric PartialDiagnostic::DiagStorageAllocator::~DiagStorageAllocator() { 12200b57cec5SDimitry Andric // Don't assert if we are in a CrashRecovery context, as this invariant may 12210b57cec5SDimitry Andric // be invalidated during a crash. 12220b57cec5SDimitry Andric assert((NumFreeListEntries == NumCached || 12230b57cec5SDimitry Andric llvm::CrashRecoveryContext::isRecoveringFromCrash()) && 12240b57cec5SDimitry Andric "A partial is on the lam"); 12250b57cec5SDimitry Andric } 12260b57cec5SDimitry Andric 12270b57cec5SDimitry Andric char DiagnosticError::ID; 1228