//======- AttributeCommonInfo.h - Base info about Attributes-----*- C++ -*-===//
 
//
 
// 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 defines the AttributeCommonInfo type, which is the base for a
 
// ParsedAttr and is used by Attr as a way to share info between the two.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H
 
#define LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H
 
#include "clang/Basic/SourceLocation.h"
 
 
 
namespace clang {
 
class IdentifierInfo;
 
class ASTRecordWriter;
 
 
 
class AttributeCommonInfo {
 
public:
 
  /// The style used to specify an attribute.
 
  enum Syntax {
 
    /// __attribute__((...))
 
    AS_GNU,
 
 
 
    /// [[...]]
 
    AS_CXX11,
 
 
 
    /// [[...]]
 
    AS_C2x,
 
 
 
    /// __declspec(...)
 
    AS_Declspec,
 
 
 
    /// [uuid("...")] class Foo
 
    AS_Microsoft,
 
 
 
    /// __ptr16, alignas(...), etc.
 
    AS_Keyword,
 
 
 
    /// #pragma ...
 
    AS_Pragma,
 
 
 
    // Note TableGen depends on the order above.  Do not add or change the order
 
    // without adding related code to TableGen/ClangAttrEmitter.cpp.
 
    /// Context-sensitive version of a keyword attribute.
 
    AS_ContextSensitiveKeyword,
 
 
 
    /// <vardecl> : <semantic>
 
    AS_HLSLSemantic,
 
  };
 
  enum Kind {
 
#define PARSED_ATTR(NAME) AT_##NAME,
 
#include "clang/Sema/AttrParsedAttrList.inc"
 
#undef PARSED_ATTR
 
    NoSemaHandlerAttribute,
 
    IgnoredAttribute,
 
    UnknownAttribute,
 
  };
 
 
 
private:
 
  const IdentifierInfo *AttrName = nullptr;
 
  const IdentifierInfo *ScopeName = nullptr;
 
  SourceRange AttrRange;
 
  const SourceLocation ScopeLoc;
 
  // Corresponds to the Kind enum.
 
  unsigned AttrKind : 16;
 
  /// Corresponds to the Syntax enum.
 
  unsigned SyntaxUsed : 4;
 
  unsigned SpellingIndex : 4;
 
 
 
protected:
 
  static constexpr unsigned SpellingNotCalculated = 0xf;
 
 
 
public:
 
  AttributeCommonInfo(SourceRange AttrRange)
 
      : AttrRange(AttrRange), ScopeLoc(), AttrKind(0), SyntaxUsed(0),
 
        SpellingIndex(SpellingNotCalculated) {}
 
 
 
  AttributeCommonInfo(SourceLocation AttrLoc)
 
      : AttrRange(AttrLoc), ScopeLoc(), AttrKind(0), SyntaxUsed(0),
 
        SpellingIndex(SpellingNotCalculated) {}
 
 
 
  AttributeCommonInfo(const IdentifierInfo *AttrName,
 
                      const IdentifierInfo *ScopeName, SourceRange AttrRange,
 
                      SourceLocation ScopeLoc, Syntax SyntaxUsed)
 
      : AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange),
 
        ScopeLoc(ScopeLoc),
 
        AttrKind(getParsedKind(AttrName, ScopeName, SyntaxUsed)),
 
        SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingNotCalculated) {}
 
 
 
  AttributeCommonInfo(const IdentifierInfo *AttrName,
 
                      const IdentifierInfo *ScopeName, SourceRange AttrRange,
 
                      SourceLocation ScopeLoc, Kind AttrKind, Syntax SyntaxUsed)
 
      : AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange),
 
        ScopeLoc(ScopeLoc), AttrKind(AttrKind), SyntaxUsed(SyntaxUsed),
 
        SpellingIndex(SpellingNotCalculated) {}
 
 
 
  AttributeCommonInfo(const IdentifierInfo *AttrName,
 
                      const IdentifierInfo *ScopeName, SourceRange AttrRange,
 
                      SourceLocation ScopeLoc, Kind AttrKind, Syntax SyntaxUsed,
 
                      unsigned Spelling)
 
      : AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange),
 
        ScopeLoc(ScopeLoc), AttrKind(AttrKind), SyntaxUsed(SyntaxUsed),
 
        SpellingIndex(Spelling) {}
 
 
 
  AttributeCommonInfo(const IdentifierInfo *AttrName, SourceRange AttrRange,
 
                      Syntax SyntaxUsed)
 
      : AttrName(AttrName), ScopeName(nullptr), AttrRange(AttrRange),
 
        ScopeLoc(), AttrKind(getParsedKind(AttrName, ScopeName, SyntaxUsed)),
 
        SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingNotCalculated) {}
 
 
 
  AttributeCommonInfo(SourceRange AttrRange, Kind K, Syntax SyntaxUsed)
 
      : AttrName(nullptr), ScopeName(nullptr), AttrRange(AttrRange), ScopeLoc(),
 
        AttrKind(K), SyntaxUsed(SyntaxUsed),
 
        SpellingIndex(SpellingNotCalculated) {}
 
 
 
  AttributeCommonInfo(SourceRange AttrRange, Kind K, Syntax SyntaxUsed,
 
                      unsigned Spelling)
 
      : AttrName(nullptr), ScopeName(nullptr), AttrRange(AttrRange), ScopeLoc(),
 
        AttrKind(K), SyntaxUsed(SyntaxUsed), SpellingIndex(Spelling) {}
 
 
 
  AttributeCommonInfo(AttributeCommonInfo &&) = default;
 
  AttributeCommonInfo(const AttributeCommonInfo &) = default;
 
 
 
  Kind getParsedKind() const { return Kind(AttrKind); }
 
  Syntax getSyntax() const { return Syntax(SyntaxUsed); }
 
  const IdentifierInfo *getAttrName() const { return AttrName; }
 
  SourceLocation getLoc() const { return AttrRange.getBegin(); }
 
  SourceRange getRange() const { return AttrRange; }
 
  void setRange(SourceRange R) { AttrRange = R; }
 
 
 
  bool hasScope() const { return ScopeName; }
 
  const IdentifierInfo *getScopeName() const { return ScopeName; }
 
  SourceLocation getScopeLoc() const { return ScopeLoc; }
 
 
 
  /// Gets the normalized full name, which consists of both scope and name and
 
  /// with surrounding underscores removed as appropriate (e.g.
 
  /// __gnu__::__attr__ will be normalized to gnu::attr).
 
  std::string getNormalizedFullName() const;
 
 
 
  bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
 
  bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; }
 
 
 
  bool isGNUScope() const;
 
  bool isClangScope() const;
 
 
 
  bool isAlignasAttribute() const {
 
    // FIXME: Use a better mechanism to determine this.
 
    // We use this in `isCXX11Attribute` below, so it _should_ only return
 
    // true for the `alignas` spelling, but it currently also returns true
 
    // for the `_Alignas` spelling, which only exists in C11. Distinguishing
 
    // between the two is important because they behave differently:
 
    // - `alignas` may only appear in the attribute-specifier-seq before
 
    //   the decl-specifier-seq and is therefore associated with the
 
    //   declaration.
 
    // - `_Alignas` may appear anywhere within the declaration-specifiers
 
    //   and is therefore associated with the `DeclSpec`.
 
    // It's not clear how best to fix this:
 
    // - We have the necessary information in the form of the `SpellingIndex`,
 
    //   but we would need to compare against AlignedAttr::Keyword_alignas,
 
    //   and we can't depend on clang/AST/Attr.h here.
 
    // - We could test `getAttrName()->getName() == "alignas"`, but this is
 
    //   inefficient.
 
    return getParsedKind() == AT_Aligned && isKeywordAttribute();
 
  }
 
 
 
  bool isCXX11Attribute() const {
 
    return SyntaxUsed == AS_CXX11 || isAlignasAttribute();
 
  }
 
 
 
  bool isC2xAttribute() const { return SyntaxUsed == AS_C2x; }
 
 
 
  /// The attribute is spelled [[]] in either C or C++ mode, including standard
 
  /// attributes spelled with a keyword, like alignas.
 
  bool isStandardAttributeSyntax() const {
 
    return isCXX11Attribute() || isC2xAttribute();
 
  }
 
 
 
  bool isGNUAttribute() const { return SyntaxUsed == AS_GNU; }
 
 
 
  bool isKeywordAttribute() const {
 
    return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
 
  }
 
 
 
  bool isContextSensitiveKeywordAttribute() const {
 
    return SyntaxUsed == AS_ContextSensitiveKeyword;
 
  }
 
 
 
  unsigned getAttributeSpellingListIndex() const {
 
    assert((isAttributeSpellingListCalculated() || AttrName) &&
 
           "Spelling cannot be found");
 
    return isAttributeSpellingListCalculated()
 
               ? SpellingIndex
 
               : calculateAttributeSpellingListIndex();
 
  }
 
  void setAttributeSpellingListIndex(unsigned V) { SpellingIndex = V; }
 
 
 
  static Kind getParsedKind(const IdentifierInfo *Name,
 
                            const IdentifierInfo *Scope, Syntax SyntaxUsed);
 
 
 
private:
 
  /// Get an index into the attribute spelling list
 
  /// defined in Attr.td. This index is used by an attribute
 
  /// to pretty print itself.
 
  unsigned calculateAttributeSpellingListIndex() const;
 
 
 
  friend class clang::ASTRecordWriter;
 
  // Used exclusively by ASTDeclWriter to get the raw spelling list state.
 
  unsigned getAttributeSpellingListIndexRaw() const { return SpellingIndex; }
 
 
 
protected:
 
  bool isAttributeSpellingListCalculated() const {
 
    return SpellingIndex != SpellingNotCalculated;
 
  }
 
};
 
} // namespace clang
 
 
 
#endif // LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H