return import(*From);
}
- // Helper for chaining together multiple imports. If an error is detected,
- // subsequent imports will return default constructed nodes, so that failure
- // can be detected with a single conditional branch after a sequence of
- // imports.
- template <typename T> T importChecked(Error &Err, const T &From) {
- // Don't attempt to import nodes if we hit an error earlier.
- if (Err)
- return T{};
- Expected<T> MaybeVal = import(From);
- if (!MaybeVal) {
- Err = MaybeVal.takeError();
- return T{};
- }
- return *MaybeVal;
- }
-
ExplicitSpecifier importExplicitSpecifier(Error &Err,
ExplicitSpecifier ESpec);
ExpectedStmt VisitCXXTypeidExpr(CXXTypeidExpr *E);
ExpectedStmt VisitCXXFoldExpr(CXXFoldExpr *E);
+ // Helper for chaining together multiple imports. If an error is detected,
+ // subsequent imports will return default constructed nodes, so that failure
+ // can be detected with a single conditional branch after a sequence of
+ // imports.
+ template <typename T> T importChecked(Error &Err, const T &From) {
+ // Don't attempt to import nodes if we hit an error earlier.
+ if (Err)
+ return T{};
+ Expected<T> MaybeVal = import(From);
+ if (!MaybeVal) {
+ Err = MaybeVal.takeError();
+ return T{};
+ }
+ return *MaybeVal;
+ }
+
template<typename IIter, typename OIter>
Error ImportArrayChecked(IIter Ibegin, IIter Iend, OIter Obegin) {
using ItemT = std::remove_reference_t<decltype(*Obegin)>;
return ToContext.getTrivialTypeSourceInfo(*TOrErr, *BeginLocOrErr);
}
+// To use this object, it should be created before the new attribute is created,
+// and destructed after it is created. The construction already performs the
+// import of the data.
+template <typename T> struct AttrArgImporter {
+ AttrArgImporter<T>(const AttrArgImporter<T> &) = delete;
+ AttrArgImporter<T>(AttrArgImporter<T> &&) = default;
+ AttrArgImporter<T> &operator=(const AttrArgImporter<T> &) = delete;
+ AttrArgImporter<T> &operator=(AttrArgImporter<T> &&) = default;
+
+ AttrArgImporter(ASTNodeImporter &I, Error &Err, const T &From)
+ : To(I.importChecked(Err, From)) {}
+
+ const T &value() { return To; }
+
+private:
+ T To;
+};
+
+// To use this object, it should be created before the new attribute is created,
+// and destructed after it is created. The construction already performs the
+// import of the data. The array data is accessible in a pointer form, this form
+// is used by the attribute classes. This object should be created once for the
+// array data to be imported (the array size is not imported, just copied).
+template <typename T> struct AttrArgArrayImporter {
+ AttrArgArrayImporter<T>(const AttrArgArrayImporter<T> &) = delete;
+ AttrArgArrayImporter<T>(AttrArgArrayImporter<T> &&) = default;
+ AttrArgArrayImporter<T> &operator=(const AttrArgArrayImporter<T> &) = delete;
+ AttrArgArrayImporter<T> &operator=(AttrArgArrayImporter<T> &&) = default;
+
+ AttrArgArrayImporter(ASTNodeImporter &I, Error &Err,
+ const llvm::iterator_range<T *> &From,
+ unsigned ArraySize) {
+ if (Err)
+ return;
+ To.reserve(ArraySize);
+ Err = I.ImportContainerChecked(From, To);
+ }
+
+ T *value() { return To.data(); }
+
+private:
+ llvm::SmallVector<T, 2> To;
+};
+
+class AttrImporter {
+ Error Err = Error::success();
+ ASTImporter &Importer;
+ ASTNodeImporter NImporter;
+
+public:
+ AttrImporter(ASTImporter &I) : Importer(I), NImporter(I) {}
+
+ // Create an "importer" for an attribute parameter.
+ // Result of the 'value()' of that object is to be passed to the function
+ // 'createImpoprtedAttr', in the order that is expected by the attribute
+ // class.
+ template <class T> AttrArgImporter<T> importArg(const T &From) {
+ return AttrArgImporter<T>(NImporter, Err, From);
+ }
+
+ // Create an "importer" for an attribute parameter that has array type.
+ // Result of the 'value()' of that object is to be passed to the function
+ // 'createImpoprtedAttr', then the size of the array as next argument.
+ template <typename T>
+ AttrArgArrayImporter<T> importArrayArg(const llvm::iterator_range<T *> &From,
+ unsigned ArraySize) {
+ return AttrArgArrayImporter<T>(NImporter, Err, From, ArraySize);
+ }
+
+ // Create an attribute object with the specified arguments.
+ // The 'FromAttr' is the original (not imported) attribute, the 'ImportedArg'
+ // should be values that are passed to the 'Create' function of the attribute.
+ // (The 'Create' with 'ASTContext' first and 'AttributeCommonInfo' last is
+ // used here.) As much data is copied or imported from the old attribute
+ // as possible. The passed arguments should be already imported.
+ template <typename T, typename... Arg>
+ Expected<Attr *> createImportedAttr(const T *FromAttr, Arg &&...ImportedArg) {
+ static_assert(std::is_base_of<Attr, T>::value,
+ "T should be subclass of Attr.");
+
+ const IdentifierInfo *ToAttrName = Importer.Import(FromAttr->getAttrName());
+ const IdentifierInfo *ToScopeName =
+ Importer.Import(FromAttr->getScopeName());
+ SourceRange ToAttrRange =
+ NImporter.importChecked(Err, FromAttr->getRange());
+ SourceLocation ToScopeLoc =
+ NImporter.importChecked(Err, FromAttr->getScopeLoc());
+
+ if (Err)
+ return std::move(Err);
+
+ AttributeCommonInfo ToI(ToAttrName, ToScopeName, ToAttrRange, ToScopeLoc,
+ FromAttr->getParsedKind(), FromAttr->getSyntax(),
+ FromAttr->getAttributeSpellingListIndex());
+ // The "SemanticSpelling" is not needed to be passed to the constructor.
+ // That value is recalculated from the SpellingListIndex if needed.
+ T *ToAttr = T::Create(Importer.getToContext(),
+ std::forward<Arg>(ImportedArg)..., ToI);
+
+ ToAttr->setImplicit(FromAttr->isImplicit());
+ ToAttr->setPackExpansion(FromAttr->isPackExpansion());
+ if (auto *ToInheritableAttr = dyn_cast<InheritableAttr>(ToAttr))
+ ToInheritableAttr->setInherited(FromAttr->isInherited());
+
+ return ToAttr;
+ }
+};
+
Expected<Attr *> ASTImporter::Import(const Attr *FromAttr) {
Attr *ToAttr = nullptr;
+ // FIXME: Use AttrImporter as much as possible, try to remove the import
+ // of range from here.
SourceRange ToRange;
if (Error Err = importInto(ToRange, FromAttr->getRange()))
return std::move(Err);
ToAttr = To;
break;
}
+
+ case attr::AssertCapability: {
+ const auto *From = cast<AssertCapabilityAttr>(FromAttr);
+ AttrImporter AI(*this);
+ Expected<Attr *> ToAttrOrErr = AI.createImportedAttr(
+ From, AI.importArrayArg(From->args(), From->args_size()).value(),
+ From->args_size());
+ if (ToAttrOrErr)
+ ToAttr = *ToAttrOrErr;
+ else
+ return ToAttrOrErr.takeError();
+ break;
+ }
+
default:
// FIXME: 'clone' copies every member but some of them should be imported.
// Handle other Attrs that have parameters that should be imported.
ToSM.getBufferOrFake(ImportedID, SourceLocation()).getBuffer());
}
+struct ImportAttributes : public ASTImporterOptionSpecificTestBase {
+ void checkAttrImportCommon(const Attr *From, const Attr *To,
+ const Decl *ToD) {
+
+ // Verify that dump does not crash because invalid data.
+ ToD->dump(llvm::nulls());
+
+ EXPECT_EQ(From->getParsedKind(), To->getParsedKind());
+ EXPECT_EQ(From->getSyntax(), To->getSyntax());
+ if (From->getAttrName()) {
+ EXPECT_TRUE(To->getAttrName());
+ EXPECT_STREQ(From->getAttrName()->getNameStart(),
+ To->getAttrName()->getNameStart());
+ } else {
+ EXPECT_FALSE(To->getAttrName());
+ }
+ if (From->getScopeName()) {
+ EXPECT_TRUE(To->getScopeName());
+ EXPECT_STREQ(From->getScopeName()->getNameStart(),
+ To->getScopeName()->getNameStart());
+ } else {
+ EXPECT_FALSE(To->getScopeName());
+ }
+ EXPECT_EQ(From->getSpellingListIndex(), To->getSpellingListIndex());
+ EXPECT_STREQ(From->getSpelling(), To->getSpelling());
+ EXPECT_EQ(From->isInherited(), To->isInherited());
+ EXPECT_EQ(From->isImplicit(), To->isImplicit());
+ EXPECT_EQ(From->isPackExpansion(), To->isPackExpansion());
+ EXPECT_EQ(From->isLateParsed(), To->isLateParsed());
+ }
+
+ template <class DT, class AT>
+ void importAttr(const char *Code, AT *&FromAttr, AT *&ToAttr) {
+ static_assert(std::is_base_of<Attr, AT>::value, "AT should be an Attr");
+ static_assert(std::is_base_of<Decl, DT>::value, "DT should be a Decl");
+
+ Decl *FromTU = getTuDecl(Code, Lang_CXX11, "input.cc");
+ DT *FromD =
+ FirstDeclMatcher<DT>().match(FromTU, namedDecl(hasName("test")));
+ ASSERT_TRUE(FromD);
+
+ DT *ToD = Import(FromD, Lang_CXX11);
+ ASSERT_TRUE(ToD);
+
+ FromAttr = FromD->template getAttr<AT>();
+ ToAttr = ToD->template getAttr<AT>();
+ ASSERT_TRUE(FromAttr);
+ EXPECT_TRUE(ToAttr);
+
+ checkAttrImportCommon(FromAttr, ToAttr, ToD);
+ }
+
+ template <class T> void checkImported(const T *From, const T *To) {
+ EXPECT_TRUE(To);
+ EXPECT_NE(From, To);
+ }
+
+ template <class T>
+ void checkImportVariadicArg(const llvm::iterator_range<T **> &From,
+ const llvm::iterator_range<T **> &To) {
+ for (auto FromI = From.begin(), ToI = To.begin(); FromI != From.end();
+ ++FromI, ++ToI) {
+ ASSERT_NE(ToI, To.end());
+ checkImported(*FromI, *ToI);
+ }
+ }
+};
+
+template <>
+void ImportAttributes::checkImported<Decl>(const Decl *From, const Decl *To) {
+ EXPECT_TRUE(To);
+ EXPECT_NE(From, To);
+ EXPECT_EQ(To->getTranslationUnitDecl(),
+ ToAST->getASTContext().getTranslationUnitDecl());
+}
+
+// FIXME: Use ImportAttributes for this test.
TEST_P(ASTImporterOptionSpecificTestBase, ImportExprOfAlignmentAttr) {
// Test if import of these packed and aligned attributes does not trigger an
// error situation where source location from 'From' context is referenced in
EXPECT_TRUE(ToA);
}
+// FIXME: Use ImportAttributes for this test.
TEST_P(ASTImporterOptionSpecificTestBase, ImportFormatAttr) {
Decl *FromTU = getTuDecl(
R"(
ToAttr->getAttributeSpellingListIndex());
EXPECT_EQ(FromAttr->getType()->getName(), ToAttr->getType()->getName());
}
+
+TEST_P(ImportAttributes, ImportAssertCapability) {
+ AssertCapabilityAttr *FromAttr, *ToAttr;
+ importAttr<FunctionDecl>(
+ "void test(int A1, int A2) __attribute__((assert_capability(A1, A2)));",
+ FromAttr, ToAttr);
+ checkImportVariadicArg(FromAttr->args(), ToAttr->args());
+}
+
template <typename T>
auto ExtendWithOptions(const T &Values, const std::vector<std::string> &Args) {
auto Copy = Values;
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportWithExternalSource,
DefaultTestValuesForRunOptions);
+INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportAttributes,
+ DefaultTestValuesForRunOptions);
+
} // end namespace ast_matchers
} // end namespace clang