Index: include/clang/Basic/PartialDiagnostic.h =================================================================== --- include/clang/Basic/PartialDiagnostic.h +++ include/clang/Basic/PartialDiagnostic.h @@ -272,6 +272,89 @@ unsigned getDiagID() const { return DiagID; } + /// \brief Return the number of arguments (excluding source ranges or fix-it + /// hints) stored for this diagnostic. + unsigned getNumArgs() const { + return DiagStorage ? DiagStorage->NumDiagArgs : 0; + } + + /// \brief Return the kind of the specified index. + /// + /// Based on the kind of argument, the accessors below can be used to get + /// the value. + /// + /// \pre Idx < getNumArgs() + DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const { + assert(Idx < getNumArgs() && "Argument index out of range!"); + return (DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[Idx]; + } + + /// \brief Return the provided argument string specified by \p Idx. + /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_std_string + const std::string &getArgStdStr(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_std_string && + "invalid argument accessor!"); + return DiagStorage->DiagArgumentsStr[Idx]; + } + + /// \brief Return the specified C string argument. + /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_c_string + const char *getArgCStr(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_c_string && + "invalid argument accessor!"); + return reinterpret_cast(DiagStorage->DiagArgumentsVal[Idx]); + } + + /// \brief Return the specified signed integer argument. + /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_sint + int getArgSInt(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_sint && + "invalid argument accessor!"); + return (int)DiagStorage->DiagArgumentsVal[Idx]; + } + + /// \brief Return the specified unsigned integer argument. + /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_uint + unsigned getArgUInt(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_uint && + "invalid argument accessor!"); + return (unsigned)DiagStorage->DiagArgumentsVal[Idx]; + } + + /// \brief Return the specified IdentifierInfo argument. + /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo + const IdentifierInfo *getArgIdentifier(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo && + "invalid argument accessor!"); + return reinterpret_cast( + DiagStorage->DiagArgumentsVal[Idx]); + } + + /// \brief Return the specified non-string argument in an opaque form. + /// \pre getArgKind(Idx) != DiagnosticsEngine::ak_std_string + intptr_t getRawArg(unsigned Idx) const { + assert(getArgKind(Idx) != DiagnosticsEngine::ak_std_string && + "invalid argument accessor!"); + return DiagStorage->DiagArgumentsVal[Idx]; + } + + /// \brief Return an array reference for this diagnostic's ranges. + /// The returned array reference gets invalidated if this diagnostics's + /// storage is reset. + ArrayRef getRanges() const { + return !DiagStorage ? ArrayRef() + : llvm::makeArrayRef(DiagStorage->DiagRanges, + DiagStorage->NumDiagRanges); + } + + /// \brief Return an array reference for this diagnostic's fix-it hints. + /// + /// The returned array reference gets invalidated if another fix-it hint is + /// added to the diagnostic or if this diagnostics's storage is reset. + ArrayRef getFixItHints() const { + return DiagStorage ? DiagStorage->FixItHints : ArrayRef(); + } + void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const { if (!DiagStorage) DiagStorage = getStorage(); Index: unittests/Basic/CMakeLists.txt =================================================================== --- unittests/Basic/CMakeLists.txt +++ unittests/Basic/CMakeLists.txt @@ -5,6 +5,7 @@ add_clang_unittest(BasicTests CharInfoTest.cpp FileManagerTest.cpp + PartialDiagnosticTest.cpp SourceManagerTest.cpp VirtualFileSystemTest.cpp ) Index: unittests/Basic/PartialDiagnosticTest.cpp =================================================================== --- /dev/null +++ unittests/Basic/PartialDiagnosticTest.cpp @@ -0,0 +1,59 @@ +//===- unittests/Basic/PartialDiagnostic.cpp -- PartialDiagnostic tests ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/IdentifierTable.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +TEST(PartialDiagnosticTest, getAccessors) { + PartialDiagnostic::StorageAllocator Allocator; + + PartialDiagnostic PD(1, Allocator); + EXPECT_EQ(PD.getNumArgs(), 0); + EXPECT_EQ(PD.getRanges().size(), 0); + EXPECT_EQ(PD.getFixItHints().size(), 0); + EXPECT_TRUE(!PD.hasStorage()); + + PD << -1; + EXPECT_TRUE(PD.hasStorage()); + EXPECT_EQ(PD.getNumArgs(), 1); + EXPECT_EQ(PD.getArgKind(0), DiagnosticsEngine::ak_sint); + EXPECT_EQ(PD.getArgSInt(0), -1); + + PD << 2u; + EXPECT_EQ(PD.getArgUInt(1), 2); + + std::string Str("std::string"); + PD << Str; + EXPECT_EQ(PD.getArgStdStr(2), Str); + + const char *CStr("C-string"); + PD << CStr; + EXPECT_TRUE((const void *)PD.getArgCStr(3) == (const void *)CStr); + + IdentifierInfo II; + PD << &II; + EXPECT_TRUE(PD.getArgIdentifier(4) == &II); + EXPECT_TRUE(PD.getRawArg(4) == (intptr_t)&II); + + SourceLocation Loc1 = SourceLocation::getFromRawEncoding(1); + SourceLocation Loc2 = SourceLocation::getFromRawEncoding(2); + CharSourceRange Range(SourceRange(Loc1, Loc2), false); + PD << Range; + EXPECT_EQ(PD.getRanges().size(), 1); + EXPECT_EQ(PD.getRanges()[0].getAsRange(), Range.getAsRange()); + + FixItHint Hint = FixItHint::CreateInsertion(Loc1, "Insert"); + PD << Hint; + EXPECT_EQ(PD.getFixItHints().size(), 1); + EXPECT_EQ(PD.getFixItHints()[0].CodeToInsert, "Insert"); +}