blob: 4ba266bdc70a86a28ab76992cd2189c6109281b2 [file] [log] [blame]
//===--- Identifier.cpp - Uniqued Identifier ------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements the Identifier interface.
//
//===----------------------------------------------------------------------===//
#include "swift/AST/Identifier.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ConvertUTF.h"
#include "clang/Basic/CharInfo.h"
using namespace swift;
void *DeclBaseName::SubscriptIdentifierData =
&DeclBaseName::SubscriptIdentifierData;
void *DeclBaseName::ConstructorIdentifierData =
&DeclBaseName::ConstructorIdentifierData;
void *DeclBaseName::DestructorIdentifierData =
&DeclBaseName::DestructorIdentifierData;
raw_ostream &llvm::operator<<(raw_ostream &OS, Identifier I) {
if (I.get() == nullptr)
return OS << "_";
return OS << I.get();
}
raw_ostream &llvm::operator<<(raw_ostream &OS, DeclBaseName D) {
return OS << D.userFacingName();
}
raw_ostream &llvm::operator<<(raw_ostream &OS, DeclName I) {
if (I.isSimpleName())
return OS << I.getBaseName();
OS << I.getBaseName() << "(";
for (auto c : I.getArgumentNames()) {
OS << c << ':';
}
OS << ")";
return OS;
}
raw_ostream &llvm::operator<<(raw_ostream &OS, swift::ObjCSelector S) {
unsigned n = S.getNumArgs();
if (n == 0) {
OS << S.getSelectorPieces()[0];
return OS;
}
for (auto piece : S.getSelectorPieces()) {
if (!piece.empty())
OS << piece;
OS << ":";
}
return OS;
}
bool Identifier::isOperatorSlow() const {
StringRef data = str();
auto *s = reinterpret_cast<llvm::UTF8 const *>(data.begin()),
*end = reinterpret_cast<llvm::UTF8 const *>(data.end());
llvm::UTF32 codePoint;
llvm::ConversionResult res =
llvm::convertUTF8Sequence(&s, end, &codePoint, llvm::strictConversion);
assert(res == llvm::conversionOK && "invalid UTF-8 in identifier?!");
(void)res;
return !empty() && isOperatorStartCodePoint(codePoint);
}
int Identifier::compare(Identifier other) const {
// Handle empty identifiers.
if (empty() || other.empty()) {
if (empty() != other.empty()) {
return other.empty() ? -1 : 1;
}
return 0;
}
return str().compare(other.str());
}
int DeclName::compare(DeclName other) const {
// Compare base names.
if (int result = getBaseName().compare(other.getBaseName()))
return result;
// Compare argument names.
auto argNames = getArgumentNames();
auto otherArgNames = other.getArgumentNames();
for (unsigned i = 0, n = std::min(argNames.size(), otherArgNames.size());
i != n; ++i) {
if (int result = argNames[i].compare(otherArgNames[i]))
return result;
}
if (argNames.size() == otherArgNames.size())
return 0;
return argNames.size() < otherArgNames.size() ? -1 : 1;
}
static bool equals(ArrayRef<Identifier> idents, ArrayRef<StringRef> strings) {
if (idents.size() != strings.size())
return false;
for (size_t i = 0, e = idents.size(); i != e; ++i) {
if (!idents[i].is(strings[i]))
return false;
}
return true;
}
bool DeclName::isCompoundName(DeclBaseName baseName,
ArrayRef<StringRef> argNames) const {
return (isCompoundName() &&
getBaseName() == baseName &&
equals(getArgumentNames(), argNames));
}
bool DeclName::isCompoundName(StringRef baseName,
ArrayRef<StringRef> argNames) const {
return (isCompoundName() &&
getBaseName() == baseName &&
equals(getArgumentNames(), argNames));
}
void DeclName::dump() const {
llvm::errs() << *this << "\n";
}
StringRef DeclName::getString(llvm::SmallVectorImpl<char> &scratch,
bool skipEmptyArgumentNames) const {
{
llvm::raw_svector_ostream out(scratch);
print(out, skipEmptyArgumentNames);
}
return StringRef(scratch.data(), scratch.size());
}
llvm::raw_ostream &DeclName::print(llvm::raw_ostream &os,
bool skipEmptyArgumentNames) const {
// Print the base name.
os << getBaseName();
// If this is a simple name, we're done.
if (isSimpleName())
return os;
if (skipEmptyArgumentNames) {
// If there is more than one argument yet none of them have names,
// we're done.
if (!getArgumentNames().empty()) {
bool anyNonEmptyNames = false;
for (auto c : getArgumentNames()) {
if (!c.empty()) {
anyNonEmptyNames = true;
break;
}
}
if (!anyNonEmptyNames)
return os;
}
}
// Print the argument names.
os << "(";
for (auto c : getArgumentNames()) {
os << c << ':';
}
os << ")";
return os;
}
llvm::raw_ostream &DeclName::printPretty(llvm::raw_ostream &os) const {
return print(os, /*skipEmptyArgumentNames=*/!isSpecial());
}
ObjCSelector::ObjCSelector(ASTContext &ctx, unsigned numArgs,
ArrayRef<Identifier> pieces) {
if (numArgs == 0) {
assert(pieces.size() == 1 && "No-argument selector requires one piece");
Storage = DeclName(pieces[0]);
return;
}
assert(numArgs == pieces.size() && "Wrong number of selector pieces");
Storage = DeclName(ctx, Identifier(), pieces);
}
ObjCSelectorFamily ObjCSelector::getSelectorFamily() const {
StringRef text = getSelectorPieces().front().get();
while (!text.empty() && text[0] == '_') text = text.substr(1);
// Does the given selector start with the given string as a prefix, in the
// sense of the selector naming conventions?
// This implementation matches the one used by
// clang::Selector::getMethodFamily, to make sure we behave the same as
// Clang ARC. We're not just calling that method here because it means
// allocating a clang::IdentifierInfo, which requires a Clang ASTContext.
auto hasPrefix = [](StringRef text, StringRef prefix) {
if (!text.startswith(prefix)) return false;
if (text.size() == prefix.size()) return true;
assert(text.size() > prefix.size());
return !clang::isLowercase(text[prefix.size()]);
};
if (false) /*for #define purposes*/;
#define OBJC_SELECTOR_FAMILY(LABEL, PREFIX) \
else if (hasPrefix(text, PREFIX)) return ObjCSelectorFamily::LABEL;
#include "swift/AST/ObjCSelectorFamily.def"
else return ObjCSelectorFamily::None;
}
StringRef ObjCSelector::getString(llvm::SmallVectorImpl<char> &scratch) const {
// Fast path for zero-argument selectors.
if (getNumArgs() == 0) {
auto name = getSelectorPieces()[0];
if (name.empty())
return "";
return name.str();
}
scratch.clear();
llvm::raw_svector_ostream os(scratch);
os << *this;
return os.str();
}
void ObjCSelector::dump() const {
llvm::errs() << *this << "\n";
}