1 #include "clang/Basic/Attributes.h" 2 #include "clang/Basic/AttrSubjectMatchRules.h" 3 #include "clang/Basic/AttributeCommonInfo.h" 4 #include "clang/Basic/IdentifierTable.h" 5 #include "clang/Basic/ParsedAttrInfo.h" 6 using namespace clang; 7 8 static int hasAttributeImpl(AttributeCommonInfo::Syntax Syntax, StringRef Name, 9 StringRef ScopeName, const TargetInfo &Target, 10 const LangOptions &LangOpts) { 11 12 #include "clang/Basic/AttrHasAttributeImpl.inc" 13 14 return 0; 15 } 16 17 int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax, 18 const IdentifierInfo *Scope, const IdentifierInfo *Attr, 19 const TargetInfo &Target, const LangOptions &LangOpts) { 20 StringRef Name = Attr->getName(); 21 // Normalize the attribute name, __foo__ becomes foo. 22 if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__")) 23 Name = Name.substr(2, Name.size() - 4); 24 25 // Normalize the scope name, but only for gnu and clang attributes. 26 StringRef ScopeName = Scope ? Scope->getName() : ""; 27 if (ScopeName == "__gnu__") 28 ScopeName = "gnu"; 29 else if (ScopeName == "_Clang") 30 ScopeName = "clang"; 31 32 // As a special case, look for the omp::sequence and omp::directive 33 // attributes. We support those, but not through the typical attribute 34 // machinery that goes through TableGen. We support this in all OpenMP modes 35 // so long as double square brackets are enabled. 36 if (LangOpts.OpenMP && ScopeName == "omp") 37 return (Name == "directive" || Name == "sequence") ? 1 : 0; 38 39 int res = hasAttributeImpl(Syntax, Name, ScopeName, Target, LangOpts); 40 if (res) 41 return res; 42 43 // Check if any plugin provides this attribute. 44 for (auto &Ptr : getAttributePluginInstances()) 45 if (Ptr->hasSpelling(Syntax, Name)) 46 return 1; 47 48 return 0; 49 } 50 51 const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) { 52 switch (Rule) { 53 #define ATTR_MATCH_RULE(NAME, SPELLING, IsAbstract) \ 54 case attr::NAME: \ 55 return SPELLING; 56 #include "clang/Basic/AttrSubMatchRulesList.inc" 57 } 58 llvm_unreachable("Invalid subject match rule"); 59 } 60 61 static StringRef 62 normalizeAttrScopeName(const IdentifierInfo *Scope, 63 AttributeCommonInfo::Syntax SyntaxUsed) { 64 if (!Scope) 65 return ""; 66 67 // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name 68 // to be "clang". 69 StringRef ScopeName = Scope->getName(); 70 if (SyntaxUsed == AttributeCommonInfo::AS_CXX11 || 71 SyntaxUsed == AttributeCommonInfo::AS_C2x) { 72 if (ScopeName == "__gnu__") 73 ScopeName = "gnu"; 74 else if (ScopeName == "_Clang") 75 ScopeName = "clang"; 76 } 77 return ScopeName; 78 } 79 80 static StringRef normalizeAttrName(const IdentifierInfo *Name, 81 StringRef NormalizedScopeName, 82 AttributeCommonInfo::Syntax SyntaxUsed) { 83 // Normalize the attribute name, __foo__ becomes foo. This is only allowable 84 // for GNU attributes, and attributes using the double square bracket syntax. 85 bool ShouldNormalize = 86 SyntaxUsed == AttributeCommonInfo::AS_GNU || 87 ((SyntaxUsed == AttributeCommonInfo::AS_CXX11 || 88 SyntaxUsed == AttributeCommonInfo::AS_C2x) && 89 (NormalizedScopeName.empty() || NormalizedScopeName == "gnu" || 90 NormalizedScopeName == "clang")); 91 StringRef AttrName = Name->getName(); 92 if (ShouldNormalize && AttrName.size() >= 4 && AttrName.startswith("__") && 93 AttrName.endswith("__")) 94 AttrName = AttrName.slice(2, AttrName.size() - 2); 95 96 return AttrName; 97 } 98 99 bool AttributeCommonInfo::isGNUScope() const { 100 return ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__")); 101 } 102 103 bool AttributeCommonInfo::isClangScope() const { 104 return ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang")); 105 } 106 107 #include "clang/Sema/AttrParsedAttrKinds.inc" 108 109 static SmallString<64> normalizeName(const IdentifierInfo *Name, 110 const IdentifierInfo *Scope, 111 AttributeCommonInfo::Syntax SyntaxUsed) { 112 StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed); 113 StringRef AttrName = normalizeAttrName(Name, ScopeName, SyntaxUsed); 114 115 SmallString<64> FullName = ScopeName; 116 if (!ScopeName.empty()) { 117 assert(SyntaxUsed == AttributeCommonInfo::AS_CXX11 || 118 SyntaxUsed == AttributeCommonInfo::AS_C2x); 119 FullName += "::"; 120 } 121 FullName += AttrName; 122 123 return FullName; 124 } 125 126 AttributeCommonInfo::Kind 127 AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name, 128 const IdentifierInfo *ScopeName, 129 Syntax SyntaxUsed) { 130 return ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed); 131 } 132 133 std::string AttributeCommonInfo::getNormalizedFullName() const { 134 return static_cast<std::string>( 135 normalizeName(getAttrName(), getScopeName(), getSyntax())); 136 } 137 138 unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const { 139 // Both variables will be used in tablegen generated 140 // attribute spell list index matching code. 141 auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax()); 142 StringRef Scope = normalizeAttrScopeName(getScopeName(), Syntax); 143 StringRef Name = normalizeAttrName(getAttrName(), Scope, Syntax); 144 145 #include "clang/Sema/AttrSpellingListIndex.inc" 146 } 147