diff options
Diffstat (limited to 'include/clang/Basic/Diagnostic.h')
-rw-r--r-- | include/clang/Basic/Diagnostic.h | 276 |
1 files changed, 197 insertions, 79 deletions
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index fefc44c..e157178 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -50,13 +50,19 @@ public: /// insertion hint. CharSourceRange RemoveRange; + /// \brief Code in the specific range that should be inserted in the insertion + /// location. + CharSourceRange InsertFromRange; + /// \brief The actual code to insert at the insertion location, as a /// string. std::string CodeToInsert; + bool BeforePreviousInsertions; + /// \brief Empty code modification hint, indicating that no code /// modification is known. - FixItHint() : RemoveRange() { } + FixItHint() : BeforePreviousInsertions(false) { } bool isNull() const { return !RemoveRange.isValid(); @@ -65,11 +71,26 @@ public: /// \brief Create a code modification hint that inserts the given /// code string at a specific location. static FixItHint CreateInsertion(SourceLocation InsertionLoc, - StringRef Code) { + StringRef Code, + bool BeforePreviousInsertions = false) { FixItHint Hint; Hint.RemoveRange = CharSourceRange(SourceRange(InsertionLoc, InsertionLoc), false); Hint.CodeToInsert = Code; + Hint.BeforePreviousInsertions = BeforePreviousInsertions; + return Hint; + } + + /// \brief Create a code modification hint that inserts the given + /// code from \arg FromRange at a specific location. + static FixItHint CreateInsertionFromRange(SourceLocation InsertionLoc, + CharSourceRange FromRange, + bool BeforePreviousInsertions = false) { + FixItHint Hint; + Hint.RemoveRange = + CharSourceRange(SourceRange(InsertionLoc, InsertionLoc), false); + Hint.InsertFromRange = FromRange; + Hint.BeforePreviousInsertions = BeforePreviousInsertions; return Hint; } @@ -105,7 +126,7 @@ public: /// "report warnings as errors" and passes them off to the DiagnosticConsumer /// for reporting to the user. DiagnosticsEngine is tied to one translation unit /// and one SourceManager. -class DiagnosticsEngine : public llvm::RefCountedBase<DiagnosticsEngine> { +class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> { public: /// Level - The level of the diagnostic, after it has been through mapping. enum Level { @@ -158,8 +179,10 @@ private: unsigned ErrorLimit; // Cap of # errors emitted, 0 -> no limit. unsigned TemplateBacktraceLimit; // Cap on depth of template backtrace stack, // 0 -> no limit. + unsigned ConstexprBacktraceLimit; // Cap on depth of constexpr evaluation + // backtrace stack, 0 -> no limit. ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors? - llvm::IntrusiveRefCntPtr<DiagnosticIDs> Diags; + IntrusiveRefCntPtr<DiagnosticIDs> Diags; DiagnosticConsumer *Client; bool OwnsDiagClient; SourceManager *SourceMgr; @@ -287,7 +310,7 @@ private: unsigned NumPrevArgs, SmallVectorImpl<char> &Output, void *Cookie, - SmallVectorImpl<intptr_t> &QualTypeVals); + ArrayRef<intptr_t> QualTypeVals); void *ArgToStringCookie; ArgToStringFnTy ArgToStringFn; @@ -304,12 +327,12 @@ private: public: explicit DiagnosticsEngine( - const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &Diags, + const IntrusiveRefCntPtr<DiagnosticIDs> &Diags, DiagnosticConsumer *client = 0, bool ShouldOwnClient = true); ~DiagnosticsEngine(); - const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const { + const IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const { return Diags; } @@ -363,13 +386,25 @@ public: void setTemplateBacktraceLimit(unsigned Limit) { TemplateBacktraceLimit = Limit; } - + /// \brief Retrieve the maximum number of template instantiation - /// nodes to emit along with a given diagnostic. + /// notes to emit along with a given diagnostic. unsigned getTemplateBacktraceLimit() const { return TemplateBacktraceLimit; } - + + /// \brief Specify the maximum number of constexpr evaluation + /// notes to emit along with a given diagnostic. + void setConstexprBacktraceLimit(unsigned Limit) { + ConstexprBacktraceLimit = Limit; + } + + /// \brief Retrieve the maximum number of constexpr evaluation + /// notes to emit along with a given diagnostic. + unsigned getConstexprBacktraceLimit() const { + return ConstexprBacktraceLimit; + } + /// setIgnoreAllWarnings - When set to true, any unmapped warnings are /// ignored. If this and WarningsAsErrors are both set, then this one wins. void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; } @@ -450,18 +485,32 @@ public: bool setDiagnosticGroupMapping(StringRef Group, diag::Mapping Map, SourceLocation Loc = SourceLocation()); + /// \brief Set the warning-as-error flag for the given diagnostic. This + /// function always only operates on the current diagnostic state. + void setDiagnosticWarningAsError(diag::kind Diag, bool Enabled); + /// \brief Set the warning-as-error flag for the given diagnostic group. This /// function always only operates on the current diagnostic state. /// /// \returns True if the given group is unknown, false otherwise. bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled); + /// \brief Set the error-as-fatal flag for the given diagnostic. This function + /// always only operates on the current diagnostic state. + void setDiagnosticErrorAsFatal(diag::kind Diag, bool Enabled); + /// \brief Set the error-as-fatal flag for the given diagnostic group. This /// function always only operates on the current diagnostic state. /// /// \returns True if the given group is unknown, false otherwise. bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled); + /// \brief Add the specified mapping to all diagnostics. Mainly to be used + /// by -Wno-everything to disable all warnings but allow subsequent -W options + /// to enable specific warnings. + void setMappingToAllDiagnostics(diag::Mapping Map, + SourceLocation Loc = SourceLocation()); + bool hasErrorOccurred() const { return ErrorOccurred; } bool hasFatalErrorOccurred() const { return FatalErrorOccurred; } @@ -587,16 +636,22 @@ private: /// MaxArguments - The maximum number of arguments we can hold. We currently /// only support up to 10 arguments (%0-%9). A single diagnostic with more /// than that almost certainly has to be simplified anyway. - MaxArguments = 10 + MaxArguments = 10, + + /// MaxRanges - The maximum number of ranges we can hold. + MaxRanges = 10, + + /// MaxFixItHints - The maximum number of ranges we can hold. + MaxFixItHints = 10 }; /// NumDiagArgs - This contains the number of entries in Arguments. signed char NumDiagArgs; - /// NumRanges - This is the number of ranges in the DiagRanges array. + /// NumDiagRanges - This is the number of ranges in the DiagRanges array. unsigned char NumDiagRanges; - /// \brief The number of code modifications hints in the - /// FixItHints array. - unsigned char NumFixItHints; + /// NumDiagFixItHints - This is the number of hints in the DiagFixItHints + /// array. + unsigned char NumDiagFixItHints; /// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum /// values, with one for each argument. This specifies whether the argument @@ -614,15 +669,27 @@ private: /// sort of argument kind it is. intptr_t DiagArgumentsVal[MaxArguments]; - /// DiagRanges - The list of ranges added to this diagnostic. It currently - /// only support 10 ranges, could easily be extended if needed. - CharSourceRange DiagRanges[10]; + /// DiagRanges - The list of ranges added to this diagnostic. + CharSourceRange DiagRanges[MaxRanges]; - enum { MaxFixItHints = 6 }; + /// FixItHints - If valid, provides a hint with some code to insert, remove, + /// or modify at a particular position. + FixItHint DiagFixItHints[MaxFixItHints]; - /// FixItHints - If valid, provides a hint with some code - /// to insert, remove, or modify at a particular position. - FixItHint FixItHints[MaxFixItHints]; + DiagnosticMappingInfo makeMappingInfo(diag::Mapping Map, SourceLocation L) { + bool isPragma = L.isValid(); + DiagnosticMappingInfo MappingInfo = DiagnosticMappingInfo::Make( + Map, /*IsUser=*/true, isPragma); + + // If this is a pragma mapping, then set the diagnostic mapping flags so + // that we override command line options. + if (isPragma) { + MappingInfo.setNoWarningAsError(true); + MappingInfo.setNoErrorAsFatal(true); + } + + return MappingInfo; + } /// ProcessDiag - This is the method used to report a diagnostic that is /// finally fully formed. @@ -633,6 +700,24 @@ private: return Diags->ProcessDiag(*this); } + /// @name Diagnostic Emission + /// @{ +protected: + // Sema requires access to the following functions because the current design + // of SFINAE requires it to use its own SemaDiagnosticBuilder, which needs to + // access us directly to ensure we minimize the emitted code for the common + // Sema::Diag() patterns. + friend class Sema; + + /// \brief Emit the current diagnostic and clear the diagnostic state. + bool EmitCurrentDiagnostic(); + + unsigned getCurrentDiagID() const { return CurDiagID; } + + SourceLocation getCurrentDiagLoc() const { return CurDiagLoc; } + + /// @} + friend class ASTReader; friend class ASTWriter; }; @@ -685,37 +770,39 @@ public: /// for example. class DiagnosticBuilder { mutable DiagnosticsEngine *DiagObj; - mutable unsigned NumArgs, NumRanges, NumFixItHints; + mutable unsigned NumArgs, NumRanges, NumFixits; + + /// \brief Status variable indicating if this diagnostic is still active. + /// + // NOTE: This field is redundant with DiagObj (IsActive iff (DiagObj == 0)), + // but LLVM is not currently smart enough to eliminate the null check that + // Emit() would end up with if we used that as our status variable. + mutable bool IsActive; void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT friend class DiagnosticsEngine; explicit DiagnosticBuilder(DiagnosticsEngine *diagObj) - : DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixItHints(0) {} + : DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixits(0), IsActive(true) { + assert(diagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!"); + } friend class PartialDiagnostic; protected: - void FlushCounts(); - -public: - /// Copy constructor. When copied, this "takes" the diagnostic info from the - /// input and neuters it. - DiagnosticBuilder(const DiagnosticBuilder &D) { - DiagObj = D.DiagObj; - D.DiagObj = 0; - NumArgs = D.NumArgs; - NumRanges = D.NumRanges; - NumFixItHints = D.NumFixItHints; + void FlushCounts() { + DiagObj->NumDiagArgs = NumArgs; + DiagObj->NumDiagRanges = NumRanges; + DiagObj->NumDiagFixItHints = NumFixits; } - /// \brief Simple enumeration value used to give a name to the - /// suppress-diagnostic constructor. - enum SuppressKind { Suppress }; + /// \brief Clear out the current diagnostic. + void Clear() const { + DiagObj = 0; + IsActive = false; + } - /// \brief Create an empty DiagnosticBuilder object that represents - /// no actual diagnostic. - explicit DiagnosticBuilder(SuppressKind) - : DiagObj(0), NumArgs(0), NumRanges(0), NumFixItHints(0) { } + /// isActive - Determine whether this diagnostic is still active. + bool isActive() const { return IsActive; } /// \brief Force the diagnostic builder to emit the diagnostic now. /// @@ -724,25 +811,40 @@ public: /// /// \returns true if a diagnostic was emitted, false if the /// diagnostic was suppressed. - bool Emit(); + bool Emit() { + // If this diagnostic is inactive, then its soul was stolen by the copy ctor + // (or by a subclass, as in SemaDiagnosticBuilder). + if (!isActive()) return false; - /// Destructor - The dtor emits the diagnostic if it hasn't already - /// been emitted. - ~DiagnosticBuilder() { Emit(); } + // When emitting diagnostics, we set the final argument count into + // the DiagnosticsEngine object. + FlushCounts(); - /// isActive - Determine whether this diagnostic is still active. - bool isActive() const { return DiagObj != 0; } + // Process the diagnostic. + bool Result = DiagObj->EmitCurrentDiagnostic(); - /// \brief Retrieve the active diagnostic ID. - /// - /// \pre \c isActive() - unsigned getDiagID() const { - assert(isActive() && "DiagnosticsEngine is inactive"); - return DiagObj->CurDiagID; + // This diagnostic is dead. + Clear(); + + return Result; } - /// \brief Clear out the current diagnostic. - void Clear() { DiagObj = 0; } +public: + /// Copy constructor. When copied, this "takes" the diagnostic info from the + /// input and neuters it. + DiagnosticBuilder(const DiagnosticBuilder &D) { + DiagObj = D.DiagObj; + IsActive = D.IsActive; + D.Clear(); + NumArgs = D.NumArgs; + NumRanges = D.NumRanges; + NumFixits = D.NumFixits; + } + + /// Destructor - The dtor emits the diagnostic. + ~DiagnosticBuilder() { + Emit(); + } /// Operator bool: conversion of DiagnosticBuilder to bool always returns /// true. This allows is to be used in boolean error contexts like: @@ -750,38 +852,33 @@ public: operator bool() const { return true; } void AddString(StringRef S) const { + assert(isActive() && "Clients must not add to cleared diagnostic!"); assert(NumArgs < DiagnosticsEngine::MaxArguments && "Too many arguments to diagnostic!"); - if (DiagObj) { - DiagObj->DiagArgumentsKind[NumArgs] = DiagnosticsEngine::ak_std_string; - DiagObj->DiagArgumentsStr[NumArgs++] = S; - } + DiagObj->DiagArgumentsKind[NumArgs] = DiagnosticsEngine::ak_std_string; + DiagObj->DiagArgumentsStr[NumArgs++] = S; } void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const { + assert(isActive() && "Clients must not add to cleared diagnostic!"); assert(NumArgs < DiagnosticsEngine::MaxArguments && "Too many arguments to diagnostic!"); - if (DiagObj) { - DiagObj->DiagArgumentsKind[NumArgs] = Kind; - DiagObj->DiagArgumentsVal[NumArgs++] = V; - } + DiagObj->DiagArgumentsKind[NumArgs] = Kind; + DiagObj->DiagArgumentsVal[NumArgs++] = V; } void AddSourceRange(const CharSourceRange &R) const { - assert(NumRanges < - sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) && + assert(isActive() && "Clients must not add to cleared diagnostic!"); + assert(NumRanges < DiagnosticsEngine::MaxRanges && "Too many arguments to diagnostic!"); - if (DiagObj) - DiagObj->DiagRanges[NumRanges++] = R; + DiagObj->DiagRanges[NumRanges++] = R; } void AddFixItHint(const FixItHint &Hint) const { - assert(NumFixItHints < DiagnosticsEngine::MaxFixItHints && - "Too many fix-it hints!"); - if (NumFixItHints >= DiagnosticsEngine::MaxFixItHints) - return; // Don't crash in release builds - if (DiagObj) - DiagObj->FixItHints[NumFixItHints++] = Hint; + assert(isActive() && "Clients must not add to cleared diagnostic!"); + assert(NumFixits < DiagnosticsEngine::MaxFixItHints && + "Too many arguments to diagnostic!"); + DiagObj->DiagFixItHints[NumFixits++] = Hint; } }; @@ -849,7 +946,8 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, const FixItHint &Hint) { - DB.AddFixItHint(Hint); + if (!Hint.isNull()) + DB.AddFixItHint(Hint); return DB; } @@ -951,17 +1049,22 @@ public: return DiagObj->DiagRanges[Idx]; } + /// \brief Return an array reference for this diagnostic's ranges. + ArrayRef<CharSourceRange> getRanges() const { + return llvm::makeArrayRef(DiagObj->DiagRanges, DiagObj->NumDiagRanges); + } + unsigned getNumFixItHints() const { - return DiagObj->NumFixItHints; + return DiagObj->NumDiagFixItHints; } const FixItHint &getFixItHint(unsigned Idx) const { - return DiagObj->FixItHints[Idx]; + assert(Idx < getNumFixItHints() && "Invalid index!"); + return DiagObj->DiagFixItHints[Idx]; } const FixItHint *getFixItHints() const { - return DiagObj->NumFixItHints? - &DiagObj->FixItHints[0] : 0; + return getNumFixItHints()? DiagObj->DiagFixItHints : 0; } /// FormatDiagnostic - Format this diagnostic into a string, substituting the @@ -1012,11 +1115,20 @@ public: range_iterator range_begin() const { return Ranges.begin(); } range_iterator range_end() const { return Ranges.end(); } unsigned range_size() const { return Ranges.size(); } + + ArrayRef<CharSourceRange> getRanges() const { + return llvm::makeArrayRef(Ranges); + } + typedef std::vector<FixItHint>::const_iterator fixit_iterator; fixit_iterator fixit_begin() const { return FixIts.begin(); } fixit_iterator fixit_end() const { return FixIts.end(); } unsigned fixit_size() const { return FixIts.size(); } + + ArrayRef<FixItHint> getFixIts() const { + return llvm::makeArrayRef(FixIts); + } }; /// DiagnosticConsumer - This is an abstract interface implemented by clients of @@ -1031,6 +1143,7 @@ public: unsigned getNumErrors() const { return NumErrors; } unsigned getNumWarnings() const { return NumWarnings; } + virtual void clear() { NumWarnings = NumErrors = 0; } virtual ~DiagnosticConsumer(); @@ -1053,6 +1166,10 @@ public: /// objects made available via \see BeginSourceFile() are inaccessible. virtual void EndSourceFile() {} + /// \brief Callback to inform the diagnostic client that processing of all + /// source files has ended. + virtual void finish() {} + /// IncludeInDiagnosticCounts - This method (whose default implementation /// returns true) indicates whether the diagnostics handled by this /// DiagnosticConsumer should be included in the number of diagnostics @@ -1075,6 +1192,7 @@ public: /// IgnoringDiagConsumer - This is a diagnostic client that just ignores all /// diags. class IgnoringDiagConsumer : public DiagnosticConsumer { + virtual void anchor(); void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { // Just ignore it. |