[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-03-08 Thread Egor Zhdan via cfe-commits

egorzhdan wrote:

Apologies for the delay!
I looked into this performance hit, and it seems largely expected to me: the 
compiler spends extra time checking if there is an apinotes file for a given 
clang module with the notes for the declarations that are being processed. We 
can consider adding a Clang driver option to disable API Notes, if this 
performance regression is significant enough.

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-03-05 Thread Arthur Eubanks via cfe-commits

aeubanks wrote:

> Oh, thanks @nikic for that data point. Let me try to avoid the overhead, I'll 
> put up a patch tomorrow morning.

Did this ever happen?

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-26 Thread Egor Zhdan via cfe-commits

egorzhdan wrote:

Oh, thanks @nikic for that data point. Let me try to avoid the overhead, I'll 
put up a patch tomorrow morning.

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-26 Thread Nikita Popov via cfe-commits

nikic wrote:

FYI this change adds some overhead (about 0.2% for O0) builds 
(http://llvm-compile-time-tracker.com/compare.php?from=046682ef88a254443e8620bfd48b35bfa0a83809=440b1743ee0c8bfb7bf0c4b503bde5ab9af88dc0=instructions:u).
 Is it possible to avoid it for people not using API notes?

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-26 Thread Egor Zhdan via cfe-commits

https://github.com/egorzhdan closed 
https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-26 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (!IsUnmodified(D, Function->getReturnType(), Nullability)) {
+  QualType FnType = Function->getType();
+  Function->setType(FnType);
+}
+  } else if (auto Method = dyn_cast(D)) {
+QualType Type = Method->getReturnType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Method->setReturnType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (!isIndirectPointerType(Type))
+Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Value = dyn_cast(D)) {
+QualType Type = Value->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Value->setType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (auto Parm = dyn_cast(D)) {
+if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type))
+  Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+  }
+}
+  } else if (auto Property = dyn_cast(D)) {
+QualType Type = Property->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Property->setType(Type, Property->getTypeSourceInfo());
+
+  // Make it a property attribute if we can.
+  if (!isIndirectPointerType(Type))
+Property->setPropertyAttributes(
+ObjCPropertyAttribute::kind_null_resettable);
+}
+  }
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef ASTAllocateString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char *));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getPlaceholderAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X)
\
+  template <> struct AttrKindFor {
\
+static const attr::Kind value = attr::X;   
\
+  };
+#include "clang/Basic/AttrList.inc"
+
+/// Handle an attribute introduced by API notes.
+///
+/// \param IsAddition Whether we should add 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-26 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (!IsUnmodified(D, Function->getReturnType(), Nullability)) {
+  QualType FnType = Function->getType();
+  Function->setType(FnType);
+}
+  } else if (auto Method = dyn_cast(D)) {
+QualType Type = Method->getReturnType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Method->setReturnType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (!isIndirectPointerType(Type))
+Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Value = dyn_cast(D)) {
+QualType Type = Value->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Value->setType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (auto Parm = dyn_cast(D)) {
+if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type))
+  Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+  }
+}
+  } else if (auto Property = dyn_cast(D)) {
+QualType Type = Property->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Property->setType(Type, Property->getTypeSourceInfo());
+
+  // Make it a property attribute if we can.
+  if (!isIndirectPointerType(Type))
+Property->setPropertyAttributes(
+ObjCPropertyAttribute::kind_null_resettable);
+}
+  }
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef ASTAllocateString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char *));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getPlaceholderAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X)
\
+  template <> struct AttrKindFor {
\
+static const attr::Kind value = attr::X;   
\
+  };
+#include "clang/Basic/AttrList.inc"
+
+/// Handle an attribute introduced by API notes.
+///
+/// \param IsAddition Whether we should add 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-26 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (!IsUnmodified(D, Function->getReturnType(), Nullability)) {
+  QualType FnType = Function->getType();
+  Function->setType(FnType);
+}
+  } else if (auto Method = dyn_cast(D)) {
+QualType Type = Method->getReturnType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Method->setReturnType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (!isIndirectPointerType(Type))
+Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Value = dyn_cast(D)) {
+QualType Type = Value->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Value->setType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (auto Parm = dyn_cast(D)) {
+if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type))
+  Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+  }
+}
+  } else if (auto Property = dyn_cast(D)) {
+QualType Type = Property->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Property->setType(Type, Property->getTypeSourceInfo());
+
+  // Make it a property attribute if we can.
+  if (!isIndirectPointerType(Type))
+Property->setPropertyAttributes(
+ObjCPropertyAttribute::kind_null_resettable);
+}
+  }
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef ASTAllocateString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char *));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getPlaceholderAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X)
\
+  template <> struct AttrKindFor {
\
+static const attr::Kind value = attr::X;   
\
+  };
+#include "clang/Basic/AttrList.inc"
+
+/// Handle an attribute introduced by API notes.
+///
+/// \param IsAddition Whether we should add 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-26 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (!IsUnmodified(D, Function->getReturnType(), Nullability)) {
+  QualType FnType = Function->getType();
+  Function->setType(FnType);
+}
+  } else if (auto Method = dyn_cast(D)) {
+QualType Type = Method->getReturnType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Method->setReturnType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (!isIndirectPointerType(Type))
+Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Value = dyn_cast(D)) {
+QualType Type = Value->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Value->setType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (auto Parm = dyn_cast(D)) {
+if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type))
+  Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+  }
+}
+  } else if (auto Property = dyn_cast(D)) {
+QualType Type = Property->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Property->setType(Type, Property->getTypeSourceInfo());
+
+  // Make it a property attribute if we can.
+  if (!isIndirectPointerType(Type))
+Property->setPropertyAttributes(
+ObjCPropertyAttribute::kind_null_resettable);
+}
+  }
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef ASTAllocateString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char *));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getPlaceholderAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X)
\
+  template <> struct AttrKindFor {
\
+static const attr::Kind value = attr::X;   
\
+  };
+#include "clang/Basic/AttrList.inc"
+
+/// Handle an attribute introduced by API notes.
+///
+/// \param IsAddition Whether we should add 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-26 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (!IsUnmodified(D, Function->getReturnType(), Nullability)) {

egorzhdan wrote:

Agreed, done.

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-26 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };

egorzhdan wrote:

`State` seems a bit too generic of a name to me, and these are still `bool`s so 
they won't get more cases. I renamed `IsReplacement_t` to `IsSubstitution_t`, 
but I would prefer to leave `IsActive_t` as is.

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-26 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-26 Thread Egor Zhdan via cfe-commits

https://github.com/egorzhdan updated 
https://github.com/llvm/llvm-project/pull/78445

>From 806fe5abaeec7ad7d75d0be026bb42808d15bc41 Mon Sep 17 00:00:00 2001
From: Egor Zhdan 
Date: Wed, 17 Jan 2024 13:41:25 +
Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls

This upstreams more of the Clang API Notes functionality that is currently 
implemented in the Apple fork: 
https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes
---
 .../clang/Basic/DiagnosticSemaKinds.td|   7 +
 clang/include/clang/Sema/Sema.h   |   6 +
 clang/lib/Sema/CMakeLists.txt |   1 +
 clang/lib/Sema/SemaAPINotes.cpp   | 988 ++
 clang/lib/Sema/SemaDecl.cpp   |   4 +
 clang/lib/Sema/SemaDeclAttr.cpp   |   3 +
 clang/lib/Sema/SemaDeclCXX.cpp|   6 +-
 clang/lib/Sema/SemaDeclObjC.cpp   |   4 +
 clang/lib/Sema/SemaObjCProperty.cpp   |   5 +
 clang/lib/Sema/SemaTemplate.cpp   |   7 +
 10 files changed, 1030 insertions(+), 1 deletion(-)
 create mode 100644 clang/lib/Sema/SemaAPINotes.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ebda201361fb07..887d6120f48d2c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning<
 
 } // end of sema category
 
+let CategoryName = "API Notes Issue" in {
+
+def err_incompatible_replacement_type : Error<
+  "API notes replacement type %0 has a different size from original type %1">;
+
+} // end of API Notes category
+
 let CategoryName = "OpenMP Issue" in {
 // OpenMP support.
 def err_omp_expected_var_arg : Error<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index fcccac10f4733a..77749372b7fb65 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4883,6 +4883,12 @@ class Sema final {
   bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr ,
 bool SkipArgCountCheck = false);
 
+  /// Map any API notes provided for this declaration to attributes on the
+  /// declaration.
+  ///
+  /// Triggered by declaration-attribute processing.
+  void ProcessAPINotes(Decl *D);
+
   /// Determine if type T is a valid subject for a nonnull and similar
   /// attributes. By default, we look through references (the behavior used by
   /// nonnull), but if the second parameter is true, then we treat a reference
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 862f9d4ffb825d..e8bff07ced0cfa 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -27,6 +27,7 @@ add_clang_library(clangSema
   Sema.cpp
   SemaAccess.cpp
   SemaAttr.cpp
+  SemaAPINotes.cpp
   SemaAvailability.cpp
   SemaCXXScopeSpec.cpp
   SemaCast.cpp
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
new file mode 100644
index 00..836c633e9d2042
--- /dev/null
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -0,0 +1,988 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsSubstitution_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsSubstitution_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsSubstitution_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-24 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (!IsUnmodified(D, Function->getReturnType(), Nullability)) {
+  QualType FnType = Function->getType();
+  Function->setType(FnType);
+}
+  } else if (auto Method = dyn_cast(D)) {
+QualType Type = Method->getReturnType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Method->setReturnType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (!isIndirectPointerType(Type))
+Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Value = dyn_cast(D)) {
+QualType Type = Value->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Value->setType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (auto Parm = dyn_cast(D)) {
+if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type))
+  Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+  }
+}
+  } else if (auto Property = dyn_cast(D)) {
+QualType Type = Property->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Property->setType(Type, Property->getTypeSourceInfo());
+
+  // Make it a property attribute if we can.
+  if (!isIndirectPointerType(Type))
+Property->setPropertyAttributes(
+ObjCPropertyAttribute::kind_null_resettable);
+}
+  }
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef ASTAllocateString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char *));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getPlaceholderAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X)
\
+  template <> struct AttrKindFor {
\
+static const attr::Kind value = attr::X;   
\
+  };
+#include "clang/Basic/AttrList.inc"
+
+/// Handle an attribute introduced by API notes.
+///
+/// \param IsAddition Whether we should add 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-24 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (!IsUnmodified(D, Function->getReturnType(), Nullability)) {
+  QualType FnType = Function->getType();
+  Function->setType(FnType);
+}
+  } else if (auto Method = dyn_cast(D)) {
+QualType Type = Method->getReturnType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Method->setReturnType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (!isIndirectPointerType(Type))
+Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Value = dyn_cast(D)) {
+QualType Type = Value->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Value->setType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (auto Parm = dyn_cast(D)) {
+if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type))
+  Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+  }
+}
+  } else if (auto Property = dyn_cast(D)) {
+QualType Type = Property->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Property->setType(Type, Property->getTypeSourceInfo());
+
+  // Make it a property attribute if we can.
+  if (!isIndirectPointerType(Type))
+Property->setPropertyAttributes(
+ObjCPropertyAttribute::kind_null_resettable);
+}
+  }
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef ASTAllocateString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char *));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getPlaceholderAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X)
\
+  template <> struct AttrKindFor {
\
+static const attr::Kind value = attr::X;   
\
+  };
+#include "clang/Basic/AttrList.inc"
+
+/// Handle an attribute introduced by API notes.
+///
+/// \param IsAddition Whether we should add 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-24 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (!IsUnmodified(D, Function->getReturnType(), Nullability)) {
+  QualType FnType = Function->getType();
+  Function->setType(FnType);
+}
+  } else if (auto Method = dyn_cast(D)) {
+QualType Type = Method->getReturnType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Method->setReturnType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (!isIndirectPointerType(Type))
+Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Value = dyn_cast(D)) {
+QualType Type = Value->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Value->setType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (auto Parm = dyn_cast(D)) {
+if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type))
+  Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+  }
+}
+  } else if (auto Property = dyn_cast(D)) {
+QualType Type = Property->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Property->setType(Type, Property->getTypeSourceInfo());
+
+  // Make it a property attribute if we can.
+  if (!isIndirectPointerType(Type))
+Property->setPropertyAttributes(
+ObjCPropertyAttribute::kind_null_resettable);
+}
+  }
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef ASTAllocateString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char *));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getPlaceholderAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X)
\
+  template <> struct AttrKindFor {
\
+static const attr::Kind value = attr::X;   
\
+  };
+#include "clang/Basic/AttrList.inc"
+
+/// Handle an attribute introduced by API notes.
+///
+/// \param IsAddition Whether we should add 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-24 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (!IsUnmodified(D, Function->getReturnType(), Nullability)) {
+  QualType FnType = Function->getType();
+  Function->setType(FnType);
+}
+  } else if (auto Method = dyn_cast(D)) {
+QualType Type = Method->getReturnType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Method->setReturnType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (!isIndirectPointerType(Type))
+Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Value = dyn_cast(D)) {
+QualType Type = Value->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Value->setType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (auto Parm = dyn_cast(D)) {
+if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type))
+  Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+  }
+}
+  } else if (auto Property = dyn_cast(D)) {
+QualType Type = Property->getType();
+if (!IsUnmodified(D, Type, Nullability)) {
+  Property->setType(Type, Property->getTypeSourceInfo());
+
+  // Make it a property attribute if we can.
+  if (!isIndirectPointerType(Type))
+Property->setPropertyAttributes(
+ObjCPropertyAttribute::kind_null_resettable);
+}
+  }
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef ASTAllocateString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char *));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getPlaceholderAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X)
\
+  template <> struct AttrKindFor {
\
+static const attr::Kind value = attr::X;   
\
+  };
+#include "clang/Basic/AttrList.inc"
+
+/// Handle an attribute introduced by API notes.
+///
+/// \param IsAddition Whether we should add 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-24 Thread Saleem Abdulrasool via cfe-commits

https://github.com/compnerd approved this pull request.

Most of the new comments are nits and small readability tweaks. I still would 
like to avoid the double `dyn_cast` checks, but I don't know if this is worth 
holding up on at that point.  Thank you for the multiple rounds on this and 
sorry about the delay, the length made it daunting.

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-24 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (!IsUnmodified(D, Function->getReturnType(), Nullability)) {

compnerd wrote:

An alternative to consider: rename the function to `IsModified` and return the 
negated value so simplify the callees.

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-24 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };

compnerd wrote:

I'd consider renaming these now with the `enum class`:

```suggestion
enum class State : bool { Inactive, Active };
enum class SubstitutionType : bool { Original, Replacement };
```

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-24 Thread Saleem Abdulrasool via cfe-commits

https://github.com/compnerd edited 
https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-23 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (IsUnmodified(D, Function->getReturnType(), Nullability)) {

egorzhdan wrote:

Oops, my bad, fixed.

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-23 Thread Egor Zhdan via cfe-commits

https://github.com/egorzhdan updated 
https://github.com/llvm/llvm-project/pull/78445

>From 2e4aa8640d208767a3f560516f1b3fd8c31dee3f Mon Sep 17 00:00:00 2001
From: Egor Zhdan 
Date: Wed, 17 Jan 2024 13:41:25 +
Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls

This upstreams more of the Clang API Notes functionality that is currently 
implemented in the Apple fork: 
https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes
---
 .../clang/Basic/DiagnosticSemaKinds.td|   7 +
 clang/include/clang/Sema/Sema.h   |   6 +
 clang/lib/Sema/CMakeLists.txt |   1 +
 clang/lib/Sema/SemaAPINotes.cpp   | 989 ++
 clang/lib/Sema/SemaDecl.cpp   |   4 +
 clang/lib/Sema/SemaDeclAttr.cpp   |   3 +
 clang/lib/Sema/SemaDeclCXX.cpp|   6 +-
 clang/lib/Sema/SemaDeclObjC.cpp   |   4 +
 clang/lib/Sema/SemaObjCProperty.cpp   |   5 +
 clang/lib/Sema/SemaTemplate.cpp   |   7 +
 10 files changed, 1031 insertions(+), 1 deletion(-)
 create mode 100644 clang/lib/Sema/SemaAPINotes.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ebda201361fb07..887d6120f48d2c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning<
 
 } // end of sema category
 
+let CategoryName = "API Notes Issue" in {
+
+def err_incompatible_replacement_type : Error<
+  "API notes replacement type %0 has a different size from original type %1">;
+
+} // end of API Notes category
+
 let CategoryName = "OpenMP Issue" in {
 // OpenMP support.
 def err_omp_expected_var_arg : Error<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index fcccac10f4733a..77749372b7fb65 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4883,6 +4883,12 @@ class Sema final {
   bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr ,
 bool SkipArgCountCheck = false);
 
+  /// Map any API notes provided for this declaration to attributes on the
+  /// declaration.
+  ///
+  /// Triggered by declaration-attribute processing.
+  void ProcessAPINotes(Decl *D);
+
   /// Determine if type T is a valid subject for a nonnull and similar
   /// attributes. By default, we look through references (the behavior used by
   /// nonnull), but if the second parameter is true, then we treat a reference
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 862f9d4ffb825d..e8bff07ced0cfa 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -27,6 +27,7 @@ add_clang_library(clangSema
   Sema.cpp
   SemaAccess.cpp
   SemaAttr.cpp
+  SemaAPINotes.cpp
   SemaAvailability.cpp
   SemaCXXScopeSpec.cpp
   SemaCast.cpp
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
new file mode 100644
index 00..e75df0653c1f9b
--- /dev/null
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-23 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (IsUnmodified(D, Function->getReturnType(), Nullability)) {
+  QualType FnType = Function->getType();
+  Function->setType(FnType);
+}
+  } else if (auto Method = dyn_cast(D)) {
+QualType Type = Method->getReturnType();
+if (IsUnmodified(D, Type, Nullability)) {
+  Method->setReturnType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (!isIndirectPointerType(Type))
+Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Value = dyn_cast(D)) {
+QualType Type = Value->getType();
+if (IsUnmodified(D, Type, Nullability)) {

compnerd wrote:

And here

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-23 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (IsUnmodified(D, Function->getReturnType(), Nullability)) {
+  QualType FnType = Function->getType();
+  Function->setType(FnType);
+}
+  } else if (auto Method = dyn_cast(D)) {
+QualType Type = Method->getReturnType();
+if (IsUnmodified(D, Type, Nullability)) {
+  Method->setReturnType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (!isIndirectPointerType(Type))
+Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Value = dyn_cast(D)) {
+QualType Type = Value->getType();
+if (IsUnmodified(D, Type, Nullability)) {
+  Value->setType(Type);
+
+  // Make it a context-sensitive keyword if we can.
+  if (auto Parm = dyn_cast(D)) {
+if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type))
+  Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+  }
+}
+  } else if (auto Property = dyn_cast(D)) {
+QualType Type = Property->getType();
+if (IsUnmodified(D, Type, Nullability)) {

compnerd wrote:

And here

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-23 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (IsUnmodified(D, Function->getReturnType(), Nullability)) {

compnerd wrote:

Wait if there is no change to the nullability, why reset the type?

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-23 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  auto IsUnmodified = [&](Decl *D, QualType QT,
+  NullabilityKind Nullability) -> bool {
+QualType Original = QT;
+S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
+isa(D),
+/*OverrideExisting=*/true);
+return QT.getTypePtr() == Original.getTypePtr();
+  };
+
+  if (auto Function = dyn_cast(D)) {
+if (IsUnmodified(D, Function->getReturnType(), Nullability)) {
+  QualType FnType = Function->getType();
+  Function->setType(FnType);
+}
+  } else if (auto Method = dyn_cast(D)) {
+QualType Type = Method->getReturnType();
+if (IsUnmodified(D, Type, Nullability)) {

compnerd wrote:

Similar

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-23 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;

egorzhdan wrote:

Ah, I see, thanks for explaining! Done

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-23 Thread Egor Zhdan via cfe-commits

https://github.com/egorzhdan updated 
https://github.com/llvm/llvm-project/pull/78445

>From 40a6247d20e121d9dea0ff83a61f5e7abba7bba6 Mon Sep 17 00:00:00 2001
From: Egor Zhdan 
Date: Wed, 17 Jan 2024 13:41:25 +
Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls

This upstreams more of the Clang API Notes functionality that is currently 
implemented in the Apple fork: 
https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes
---
 .../clang/Basic/DiagnosticSemaKinds.td|   7 +
 clang/include/clang/Sema/Sema.h   |   6 +
 clang/lib/Sema/CMakeLists.txt |   1 +
 clang/lib/Sema/SemaAPINotes.cpp   | 989 ++
 clang/lib/Sema/SemaDecl.cpp   |   4 +
 clang/lib/Sema/SemaDeclAttr.cpp   |   3 +
 clang/lib/Sema/SemaDeclCXX.cpp|   6 +-
 clang/lib/Sema/SemaDeclObjC.cpp   |   4 +
 clang/lib/Sema/SemaObjCProperty.cpp   |   5 +
 clang/lib/Sema/SemaTemplate.cpp   |   7 +
 10 files changed, 1031 insertions(+), 1 deletion(-)
 create mode 100644 clang/lib/Sema/SemaAPINotes.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ebda201361fb07..887d6120f48d2c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning<
 
 } // end of sema category
 
+let CategoryName = "API Notes Issue" in {
+
+def err_incompatible_replacement_type : Error<
+  "API notes replacement type %0 has a different size from original type %1">;
+
+} // end of API Notes category
+
 let CategoryName = "OpenMP Issue" in {
 // OpenMP support.
 def err_omp_expected_var_arg : Error<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index fcccac10f4733a..77749372b7fb65 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4883,6 +4883,12 @@ class Sema final {
   bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr ,
 bool SkipArgCountCheck = false);
 
+  /// Map any API notes provided for this declaration to attributes on the
+  /// declaration.
+  ///
+  /// Triggered by declaration-attribute processing.
+  void ProcessAPINotes(Decl *D);
+
   /// Determine if type T is a valid subject for a nonnull and similar
   /// attributes. By default, we look through references (the behavior used by
   /// nonnull), but if the second parameter is true, then we treat a reference
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 862f9d4ffb825d..e8bff07ced0cfa 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -27,6 +27,7 @@ add_clang_library(clangSema
   Sema.cpp
   SemaAccess.cpp
   SemaAttr.cpp
+  SemaAPINotes.cpp
   SemaAvailability.cpp
   SemaCXXScopeSpec.cpp
   SemaCast.cpp
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
new file mode 100644
index 00..594d73753a80e0
--- /dev/null
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -0,0 +1,989 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-23 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,995 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+
+  if (Type.isNull())
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+QualType FnType = Function->getType();
+Function->setType(FnType);
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isIndirectPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isIndirectPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");

compnerd wrote:

That should allow us to get rid of this as well.

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-23 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;

compnerd wrote:

I was thinking something like:

```c++
auto IsUnmodified = [](Decl *D, QualType QT, NullabilityKind Nullability) -> 
Bool {
  QualType Original = QT;
  S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
  isa(D),
  /*OverrideExisting=*/true);
  return QT.getTypePtr() == Original.getTypePtr();
}
```

Then, we could just do an inline `if (IsUnmodified(...)) return;` allowing us 
to fold the two if slides together.

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits

https://github.com/egorzhdan updated 
https://github.com/llvm/llvm-project/pull/78445

>From c1ad33ed549affb2bdabf49be4340a6f7580b191 Mon Sep 17 00:00:00 2001
From: Egor Zhdan 
Date: Wed, 17 Jan 2024 13:41:25 +
Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls

This upstreams more of the Clang API Notes functionality that is currently 
implemented in the Apple fork: 
https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes
---
 .../clang/Basic/DiagnosticSemaKinds.td|   7 +
 clang/include/clang/Sema/Sema.h   |   6 +
 clang/lib/Sema/CMakeLists.txt |   1 +
 clang/lib/Sema/SemaAPINotes.cpp   | 995 ++
 clang/lib/Sema/SemaDecl.cpp   |   4 +
 clang/lib/Sema/SemaDeclAttr.cpp   |   3 +
 clang/lib/Sema/SemaDeclCXX.cpp|   6 +-
 clang/lib/Sema/SemaDeclObjC.cpp   |   4 +
 clang/lib/Sema/SemaObjCProperty.cpp   |   5 +
 clang/lib/Sema/SemaTemplate.cpp   |   7 +
 10 files changed, 1037 insertions(+), 1 deletion(-)
 create mode 100644 clang/lib/Sema/SemaAPINotes.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ebda201361fb07..887d6120f48d2c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning<
 
 } // end of sema category
 
+let CategoryName = "API Notes Issue" in {
+
+def err_incompatible_replacement_type : Error<
+  "API notes replacement type %0 has a different size from original type %1">;
+
+} // end of API Notes category
+
 let CategoryName = "OpenMP Issue" in {
 // OpenMP support.
 def err_omp_expected_var_arg : Error<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index fcccac10f4733a..77749372b7fb65 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4883,6 +4883,12 @@ class Sema final {
   bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr ,
 bool SkipArgCountCheck = false);
 
+  /// Map any API notes provided for this declaration to attributes on the
+  /// declaration.
+  ///
+  /// Triggered by declaration-attribute processing.
+  void ProcessAPINotes(Decl *D);
+
   /// Determine if type T is a valid subject for a nonnull and similar
   /// attributes. By default, we look through references (the behavior used by
   /// nonnull), but if the second parameter is true, then we treat a reference
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 862f9d4ffb825d..e8bff07ced0cfa 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -27,6 +27,7 @@ add_clang_library(clangSema
   Sema.cpp
   SemaAccess.cpp
   SemaAttr.cpp
+  SemaAPINotes.cpp
   SemaAvailability.cpp
   SemaCXXScopeSpec.cpp
   SemaCast.cpp
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
new file mode 100644
index 00..9b19d3a3eb9ef2
--- /dev/null
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -0,0 +1,995 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;

egorzhdan wrote:

Hmm, not sure I follow, what can we convert to a lambda? We could theoretically 
convert the `dyn_cast`s to a `switch`, but that would mean we'd have to list 
all possible kinds of a `FunctionDecl` here, for instance.

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));

egorzhdan wrote:

Oh, good idea, let's do that!

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits

https://github.com/egorzhdan updated 
https://github.com/llvm/llvm-project/pull/78445

>From e7577bb881ee32e92037c1f10e63ac81756a4b66 Mon Sep 17 00:00:00 2001
From: Egor Zhdan 
Date: Wed, 17 Jan 2024 13:41:25 +
Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls

This upstreams more of the Clang API Notes functionality that is currently 
implemented in the Apple fork: 
https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes
---
 .../clang/Basic/DiagnosticSemaKinds.td|7 +
 clang/include/clang/Sema/Sema.h   |6 +
 clang/lib/Sema/CMakeLists.txt |1 +
 clang/lib/Sema/SemaAPINotes.cpp   | 1000 +
 clang/lib/Sema/SemaDecl.cpp   |4 +
 clang/lib/Sema/SemaDeclAttr.cpp   |3 +
 clang/lib/Sema/SemaDeclCXX.cpp|6 +-
 clang/lib/Sema/SemaDeclObjC.cpp   |4 +
 clang/lib/Sema/SemaObjCProperty.cpp   |5 +
 clang/lib/Sema/SemaTemplate.cpp   |7 +
 10 files changed, 1042 insertions(+), 1 deletion(-)
 create mode 100644 clang/lib/Sema/SemaAPINotes.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ebda201361fb07..887d6120f48d2c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning<
 
 } // end of sema category
 
+let CategoryName = "API Notes Issue" in {
+
+def err_incompatible_replacement_type : Error<
+  "API notes replacement type %0 has a different size from original type %1">;
+
+} // end of API Notes category
+
 let CategoryName = "OpenMP Issue" in {
 // OpenMP support.
 def err_omp_expected_var_arg : Error<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index fcccac10f4733a..77749372b7fb65 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4883,6 +4883,12 @@ class Sema final {
   bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr ,
 bool SkipArgCountCheck = false);
 
+  /// Map any API notes provided for this declaration to attributes on the
+  /// declaration.
+  ///
+  /// Triggered by declaration-attribute processing.
+  void ProcessAPINotes(Decl *D);
+
   /// Determine if type T is a valid subject for a nonnull and similar
   /// attributes. By default, we look through references (the behavior used by
   /// nonnull), but if the second parameter is true, then we treat a reference
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 862f9d4ffb825d..e8bff07ced0cfa 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -27,6 +27,7 @@ add_clang_library(clangSema
   Sema.cpp
   SemaAccess.cpp
   SemaAttr.cpp
+  SemaAPINotes.cpp
   SemaAvailability.cpp
   SemaCXXScopeSpec.cpp
   SemaCast.cpp
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
new file mode 100644
index 00..5a126ecc4016e4
--- /dev/null
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -0,0 +1,1000 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {

egorzhdan wrote:

Fixed

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {

egorzhdan wrote:

Renamed it to `ASTAllocateString`.

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));

egorzhdan wrote:

Good catch! That should be `alignof(char *)`.

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;

egorzhdan wrote:

Yeap, done

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {

egorzhdan wrote:

Alright, renamed it

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };

egorzhdan wrote:

Done

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };

egorzhdan wrote:

Done

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits

https://github.com/egorzhdan updated 
https://github.com/llvm/llvm-project/pull/78445

>From 76876c599efe1a51019407a261a812891b362a47 Mon Sep 17 00:00:00 2001
From: Egor Zhdan 
Date: Wed, 17 Jan 2024 13:41:25 +
Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls

This upstreams more of the Clang API Notes functionality that is currently 
implemented in the Apple fork: 
https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes
---
 .../clang/Basic/DiagnosticSemaKinds.td|7 +
 clang/include/clang/Sema/Sema.h   |6 +
 clang/lib/Sema/CMakeLists.txt |1 +
 clang/lib/Sema/SemaAPINotes.cpp   | 1003 +
 clang/lib/Sema/SemaDecl.cpp   |4 +
 clang/lib/Sema/SemaDeclAttr.cpp   |3 +
 clang/lib/Sema/SemaDeclCXX.cpp|6 +-
 clang/lib/Sema/SemaDeclObjC.cpp   |4 +
 clang/lib/Sema/SemaObjCProperty.cpp   |5 +
 clang/lib/Sema/SemaTemplate.cpp   |7 +
 10 files changed, 1045 insertions(+), 1 deletion(-)
 create mode 100644 clang/lib/Sema/SemaAPINotes.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ebda201361fb07..887d6120f48d2c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning<
 
 } // end of sema category
 
+let CategoryName = "API Notes Issue" in {
+
+def err_incompatible_replacement_type : Error<
+  "API notes replacement type %0 has a different size from original type %1">;
+
+} // end of API Notes category
+
 let CategoryName = "OpenMP Issue" in {
 // OpenMP support.
 def err_omp_expected_var_arg : Error<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index fcccac10f4733a..77749372b7fb65 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4883,6 +4883,12 @@ class Sema final {
   bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr ,
 bool SkipArgCountCheck = false);
 
+  /// Map any API notes provided for this declaration to attributes on the
+  /// declaration.
+  ///
+  /// Triggered by declaration-attribute processing.
+  void ProcessAPINotes(Decl *D);
+
   /// Determine if type T is a valid subject for a nonnull and similar
   /// attributes. By default, we look through references (the behavior used by
   /// nonnull), but if the second parameter is true, then we treat a reference
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 862f9d4ffb825d..e8bff07ced0cfa 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -27,6 +27,7 @@ add_clang_library(clangSema
   Sema.cpp
   SemaAccess.cpp
   SemaAttr.cpp
+  SemaAPINotes.cpp
   SemaAvailability.cpp
   SemaCXXScopeSpec.cpp
   SemaCast.cpp
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
new file mode 100644
index 00..f1b0b04391d756
--- /dev/null
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -0,0 +1,1003 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum class IsActive_t : bool { Inactive, Active };
+enum class IsReplacement_t : bool { Original, Replacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::Active),
+IsReplacement(Replacement == IsReplacement_t::Replacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isIndirectPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-22 Thread Egor Zhdan via cfe-commits

https://github.com/egorzhdan updated 
https://github.com/llvm/llvm-project/pull/78445

>From 9e370f99cbee234efc37ec3bbb13b7bfbdcb67a4 Mon Sep 17 00:00:00 2001
From: Egor Zhdan 
Date: Wed, 17 Jan 2024 13:41:25 +
Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls

This upstreams more of the Clang API Notes functionality that is currently 
implemented in the Apple fork: 
https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes
---
 .../clang/Basic/DiagnosticSemaKinds.td|7 +
 clang/include/clang/Sema/Sema.h   |6 +
 clang/lib/Sema/CMakeLists.txt |1 +
 clang/lib/Sema/SemaAPINotes.cpp   | 1014 +
 clang/lib/Sema/SemaDecl.cpp   |4 +
 clang/lib/Sema/SemaDeclAttr.cpp   |3 +
 clang/lib/Sema/SemaDeclCXX.cpp|6 +-
 clang/lib/Sema/SemaDeclObjC.cpp   |4 +
 clang/lib/Sema/SemaObjCProperty.cpp   |5 +
 clang/lib/Sema/SemaTemplate.cpp   |7 +
 10 files changed, 1056 insertions(+), 1 deletion(-)
 create mode 100644 clang/lib/Sema/SemaAPINotes.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ebda201361fb07..887d6120f48d2c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning<
 
 } // end of sema category
 
+let CategoryName = "API Notes Issue" in {
+
+def err_incompatible_replacement_type : Error<
+  "API notes replacement type %0 has a different size from original type %1">;
+
+} // end of API Notes category
+
 let CategoryName = "OpenMP Issue" in {
 // OpenMP support.
 def err_omp_expected_var_arg : Error<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index fcccac10f4733a..77749372b7fb65 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4883,6 +4883,12 @@ class Sema final {
   bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr ,
 bool SkipArgCountCheck = false);
 
+  /// Map any API notes provided for this declaration to attributes on the
+  /// declaration.
+  ///
+  /// Triggered by declaration-attribute processing.
+  void ProcessAPINotes(Decl *D);
+
   /// Determine if type T is a valid subject for a nonnull and similar
   /// attributes. By default, we look through references (the behavior used by
   /// nonnull), but if the second parameter is true, then we treat a reference
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 862f9d4ffb825d..e8bff07ced0cfa 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -27,6 +27,7 @@ add_clang_library(clangSema
   Sema.cpp
   SemaAccess.cpp
   SemaAttr.cpp
+  SemaAPINotes.cpp
   SemaAvailability.cpp
   SemaCXXScopeSpec.cpp
   SemaCast.cpp
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
new file mode 100644
index 00..0a04a998918f6f
--- /dev/null
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));

compnerd wrote:

Should this be `alignof(char)` or `alignof(char *)`?

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {

compnerd wrote:

```suggestion
static AttributeCommonInfo getPlaceholderAttrInfo() {
```

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;

compnerd wrote:

How about converting this to a lambda and collapsing the subsequent cast and 
check? The `dyn_cast` is not exactly free and should simplify the code flow at 
the small cost of duplication of the call to the lambda.

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {

compnerd wrote:

How about `ASTAllocString` or `ASTDuplicateString`?

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;

compnerd wrote:

Could we get away with:

```
if (Type.isNull())
  return;
```

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };

compnerd wrote:

```suggestion
enum IsReplacement_t : bool { Original, Replacement };
```

Similarly, consider `enum class`?

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));
+  } else if (auto Method = dyn_cast(D)) {
+Method->setReturnType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (!isMultiLevelPointerType(Type))
+  Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+  Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+
+  } else if (auto Value = dyn_cast(D)) {
+Value->setType(Type);
+
+// Make it a context-sensitive keyword if we can.
+if (auto Parm = dyn_cast(D)) {
+  if (Parm->isObjCMethodParameter() && !isMultiLevelPointerType(Type))
+Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
+Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
+}
+  } else if (auto Property = dyn_cast(D)) {
+Property->setType(Type, Property->getTypeSourceInfo());
+
+// Make it a property attribute if we can.
+if (!isMultiLevelPointerType(Type))
+  Property->setPropertyAttributes(
+  ObjCPropertyAttribute::kind_null_resettable);
+
+  } else
+llvm_unreachable("cannot handle nullability here");
+}
+
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext , StringRef String) {
+  void *mem = Ctx.Allocate(String.size(), alignof(char));
+  memcpy(mem, String.data(), String.size());
+  return StringRef(static_cast(mem), String.size());
+}
+
+static AttributeCommonInfo getDummyAttrInfo() {
+  return AttributeCommonInfo(SourceRange(),
+ AttributeCommonInfo::UnknownAttribute,
+ {AttributeCommonInfo::AS_GNU,
+  /*Spelling*/ 0, /*IsAlignas*/ false,
+  /*IsRegularKeywordAttribute*/ false});
+}
+
+namespace {
+template  struct AttrKindFor {};
+
+#define ATTR(X) 

[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static void applyNullability(Sema , Decl *D, NullabilityKind Nullability,
+ VersionedInfoMetadata Metadata) {
+  if (!Metadata.IsActive)
+return;
+
+  QualType Type;
+
+  // Nullability for a function/method appertains to the retain type.
+  if (auto Function = dyn_cast(D))
+Type = Function->getReturnType();
+  else if (auto Method = dyn_cast(D))
+Type = Method->getReturnType();
+  else if (auto Value = dyn_cast(D))
+Type = Value->getType();
+  else if (auto Property = dyn_cast(D))
+Type = Property->getType();
+  else
+return;
+
+  // Check the nullability specifier on this type.
+  QualType OrigType = Type;
+  S.CheckImplicitNullabilityTypeSpecifier(Type, Nullability, D->getLocation(),
+  isa(D),
+  /*overrideExisting=*/true);
+  if (Type.getTypePtr() == OrigType.getTypePtr())
+return;
+
+  if (auto Function = dyn_cast(D)) {
+const FunctionType *FnType = Function->getType()->castAs();
+if (const FunctionProtoType *Proto = dyn_cast(FnType))
+  Function->setType(S.Context.getFunctionType(Type, Proto->getParamTypes(),
+  Proto->getExtProtoInfo()));
+else
+  Function->setType(
+  S.Context.getFunctionNoProtoType(Type, FnType->getExtInfo()));

compnerd wrote:

Can we not use a QualType for the new type and then call `Function->setType` 
once?

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {

compnerd wrote:

Perhaps `IsIndirectPointer`?

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-21 Thread Saleem Abdulrasool via cfe-commits


@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };

compnerd wrote:

```suggestion
enum IsActive_t : bool { Inactive, Active };
```

Should we consider `enum class`?

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-09 Thread Egor Zhdan via cfe-commits

egorzhdan wrote:

@compnerd ping ;)

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-02-02 Thread Egor Zhdan via cfe-commits

egorzhdan wrote:

@compnerd ping! ;)

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-01-26 Thread Egor Zhdan via cfe-commits

egorzhdan wrote:

@compnerd ping :)

https://github.com/llvm/llvm-project/pull/78445
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [APINotes] Upstream Sema logic to apply API Notes to decls (PR #78445)

2024-01-17 Thread Egor Zhdan via cfe-commits

https://github.com/egorzhdan updated 
https://github.com/llvm/llvm-project/pull/78445

>From 6fdb42e20cc07a2f378239c6b7c6182e42544f18 Mon Sep 17 00:00:00 2001
From: Egor Zhdan 
Date: Wed, 17 Jan 2024 13:41:25 +
Subject: [PATCH] [APINotes] Upstream Sema logic to apply API Notes to decls

This upstreams more of the Clang API Notes functionality that is currently 
implemented in the Apple fork: 
https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes
---
 .../clang/Basic/DiagnosticSemaKinds.td|7 +
 clang/include/clang/Sema/Sema.h   |6 +
 clang/lib/Sema/CMakeLists.txt |1 +
 clang/lib/Sema/SemaAPINotes.cpp   | 1014 +
 clang/lib/Sema/SemaDecl.cpp   |4 +
 clang/lib/Sema/SemaDeclAttr.cpp   |3 +
 clang/lib/Sema/SemaDeclCXX.cpp|6 +-
 clang/lib/Sema/SemaDeclObjC.cpp   |4 +
 clang/lib/Sema/SemaObjCProperty.cpp   |5 +
 clang/lib/Sema/SemaTemplate.cpp   |7 +
 10 files changed, 1056 insertions(+), 1 deletion(-)
 create mode 100644 clang/lib/Sema/SemaAPINotes.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 03b0122d1c08f7..b705310dd37d6c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10723,6 +10723,13 @@ def warn_imp_cast_drops_unaligned : Warning<
 
 } // end of sema category
 
+let CategoryName = "API Notes Issue" in {
+
+def err_incompatible_replacement_type : Error<
+  "API notes replacement type %0 has a different size from original type %1">;
+
+} // end of API Notes category
+
 let CategoryName = "OpenMP Issue" in {
 // OpenMP support.
 def err_omp_expected_var_arg : Error<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 2c0ad022bcf19d..f191f791741363 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4763,6 +4763,12 @@ class Sema final {
   bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr ,
 bool SkipArgCountCheck = false);
 
+  /// Map any API notes provided for this declaration to attributes on the
+  /// declaration.
+  ///
+  /// Triggered by declaration-attribute processing.
+  void ProcessAPINotes(Decl *D);
+
   /// Determine if type T is a valid subject for a nonnull and similar
   /// attributes. By default, we look through references (the behavior used by
   /// nonnull), but if the second parameter is true, then we treat a reference
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 1856a88e9a3271..4f72bce98fbbec 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -27,6 +27,7 @@ add_clang_library(clangSema
   Sema.cpp
   SemaAccess.cpp
   SemaAttr.cpp
+  SemaAPINotes.cpp
   SemaAvailability.cpp
   SemaCXXScopeSpec.cpp
   SemaCast.cpp
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
new file mode 100644
index 00..0a04a998918f6f
--- /dev/null
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -0,0 +1,1014 @@
+//===--- SemaAPINotes.cpp - API Notes Handling 
===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  This file implements the mapping from API notes to declaration attributes.
+//
+//===--===//
+
+#include "clang/APINotes/APINotesReader.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+
+namespace {
+enum IsActive_t : bool { IsNotActive, IsActive };
+enum IsReplacement_t : bool { IsNotReplacement, IsReplacement };
+
+struct VersionedInfoMetadata {
+  /// An empty version refers to unversioned metadata.
+  VersionTuple Version;
+  unsigned IsActive : 1;
+  unsigned IsReplacement : 1;
+
+  VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
+IsReplacement_t Replacement)
+  : Version(Version), IsActive(Active == IsActive_t::IsActive),
+IsReplacement(Replacement == IsReplacement_t::IsReplacement) {}
+};
+} // end anonymous namespace
+
+/// Determine whether this is a multi-level pointer type.
+static bool isMultiLevelPointerType(QualType Type) {
+  QualType Pointee = Type->getPointeeType();
+  if (Pointee.isNull())
+return false;
+
+  return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
+ Pointee->isMemberPointerType();
+}
+
+/// Apply nullability to the given declaration.
+static