// Copyright (c) 2008 Roberto Raggi // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #include "Control.h" #include "Literals.h" #include "LiteralTable.h" #include "TranslationUnit.h" #include "CoreTypes.h" #include "Symbols.h" #include "Names.h" #include #include #include #include using namespace CPlusPlus; namespace { template struct Compare; template <> struct Compare { bool operator()(const IntegerType &ty, const IntegerType &otherTy) const { return ty.kind() < otherTy.kind(); } }; template <> struct Compare { bool operator()(const FloatType &ty, const FloatType &otherTy) const { return ty.kind() < otherTy.kind(); } }; template <> struct Compare { bool operator()(const PointerToMemberType &ty, const PointerToMemberType &otherTy) const { if (ty.memberName() < otherTy.memberName()) return true; else if (ty.memberName() == otherTy.memberName()) return ty.elementType() < otherTy.elementType(); return false; } }; template <> struct Compare { bool operator()(const PointerType &ty, const PointerType &otherTy) const { return ty.elementType() < otherTy.elementType(); } }; template <> struct Compare { bool operator()(const ReferenceType &ty, const ReferenceType &otherTy) const { if (ty.elementType() < otherTy.elementType()) return true; if (ty.elementType() == otherTy.elementType()) return (int)ty.isRvalueReference() < (int)otherTy.isRvalueReference(); return false; } }; template <> struct Compare { bool operator()(const NamedType &ty, const NamedType &otherTy) const { return ty.name() < otherTy.name(); } }; template <> struct Compare { bool operator()(const ArrayType &ty, const ArrayType &otherTy) const { if (ty.size() < otherTy.size()) return true; else if (ty.size() == otherTy.size()) return ty.elementType() < otherTy.elementType(); return false; } }; template <> struct Compare { bool operator()(const AnonymousNameId &name, const AnonymousNameId &otherName) const { return name.classTokenIndex() < otherName.classTokenIndex(); } }; template <> struct Compare { bool operator()(const DestructorNameId &name, const DestructorNameId &otherName) const { return name.identifier() < otherName.identifier(); } }; template <> struct Compare { bool operator()(const OperatorNameId &name, const OperatorNameId &otherName) const { return name.kind() < otherName.kind(); } }; template <> struct Compare { bool operator()(const ConversionNameId &name, const ConversionNameId &otherName) const { return name.type() < otherName.type(); } }; template <> struct Compare { bool operator()(const TemplateNameId &name, const TemplateNameId &otherName) const { const Identifier *id = name.identifier(); const Identifier *otherId = otherName.identifier(); if (id == otherId) { // we have to differentiate TemplateNameId with respect to specialization or // instantiation if (name.isSpecialization() == otherName.isSpecialization()) { return std::lexicographical_compare(name.firstTemplateArgument(), name.lastTemplateArgument(), otherName.firstTemplateArgument(), otherName.lastTemplateArgument()); } else { return name.isSpecialization(); } } return id < otherId; } }; template <> struct Compare { bool operator()(const QualifiedNameId &name, const QualifiedNameId &otherName) const { if (name.base() == otherName.base()) return name.name() < otherName.name(); return name.base() < otherName.base(); } }; template <> struct Compare { bool operator()(const SelectorNameId &name, const SelectorNameId &otherName) const { if (name.hasArguments() == otherName.hasArguments()) return std::lexicographical_compare(name.firstName(), name.lastName(), otherName.firstName(), otherName.lastName()); return name.hasArguments() < otherName.hasArguments(); } }; template class Table: public std::set > { typedef std::set > _Base; public: T *intern(const T &element) { return const_cast(&*_Base::insert(element).first); } }; } // end of anonymous namespace template static void delete_array_entries(Iterator first, Iterator last) { for (; first != last; ++first) delete *first; } template static void delete_array_entries(const Array &a) { delete_array_entries(a.begin(), a.end()); } class Control::Data { public: Data(Control *control) : control(control) , translationUnit(nullptr) , diagnosticClient(nullptr) , deprecatedId(nullptr) , unavailableId(nullptr) , objcGetterId(nullptr) , objcSetterId(nullptr) , objcReadwriteId(nullptr) , objcReadonlyId(nullptr) , objcAssignId(nullptr) , objcRetainId(nullptr) , objcCopyId(nullptr) , objcNonatomicId(nullptr) , cpp11Override(nullptr) , cpp11Final(nullptr) , processor(nullptr) {} ~Data() { // symbols delete_array_entries(symbols); } const AnonymousNameId *findOrInsertAnonymousNameId(unsigned classTokenIndex) { return anonymousNameIds.intern(AnonymousNameId(classTokenIndex)); } template const TemplateNameId *findOrInsertTemplateNameId(const Identifier *id, bool isSpecialization, Iterator first, Iterator last) { return templateNameIds.intern(TemplateNameId(id, isSpecialization, first, last)); } const DestructorNameId *findOrInsertDestructorNameId(const Name *name) { return destructorNameIds.intern(DestructorNameId(name)); } const OperatorNameId *findOrInsertOperatorNameId(OperatorNameId::Kind kind) { return operatorNameIds.intern(OperatorNameId(kind)); } const ConversionNameId *findOrInsertConversionNameId(const FullySpecifiedType &type) { return conversionNameIds.intern(ConversionNameId(type)); } const QualifiedNameId *findOrInsertQualifiedNameId(const Name *base, const Name *name) { return qualifiedNameIds.intern(QualifiedNameId(base, name)); } template const SelectorNameId *findOrInsertSelectorNameId(Iterator first, Iterator last, bool hasArguments) { return selectorNameIds.intern(SelectorNameId(first, last, hasArguments)); } IntegerType *findOrInsertIntegerType(int kind) { return integerTypes.intern(IntegerType(kind)); } FloatType *findOrInsertFloatType(int kind) { return floatTypes.intern(FloatType(kind)); } PointerToMemberType *findOrInsertPointerToMemberType(const Name *memberName, const FullySpecifiedType &elementType) { return pointerToMemberTypes.intern(PointerToMemberType(memberName, elementType)); } PointerType *findOrInsertPointerType(const FullySpecifiedType &elementType) { return pointerTypes.intern(PointerType(elementType)); } ReferenceType *findOrInsertReferenceType(const FullySpecifiedType &elementType, bool rvalueRef) { return referenceTypes.intern(ReferenceType(elementType, rvalueRef)); } ArrayType *findOrInsertArrayType(const FullySpecifiedType &elementType, unsigned size) { return arrayTypes.intern(ArrayType(elementType, size)); } NamedType *findOrInsertNamedType(const Name *name) { return namedTypes.intern(NamedType(name)); } Declaration *newDeclaration(unsigned sourceLocation, const Name *name) { Declaration *declaration = new Declaration(translationUnit, sourceLocation, name); symbols.push_back(declaration); return declaration; } EnumeratorDeclaration *newEnumeratorDeclaration(unsigned sourceLocation, const Name *name) { EnumeratorDeclaration *decl = new EnumeratorDeclaration(translationUnit, sourceLocation, name); symbols.push_back(decl); return decl; } Argument *newArgument(unsigned sourceLocation, const Name *name) { Argument *argument = new Argument(translationUnit, sourceLocation, name); symbols.push_back(argument); return argument; } TypenameArgument *newTypenameArgument(unsigned sourceLocation, const Name *name) { TypenameArgument *argument = new TypenameArgument(translationUnit, sourceLocation, name); symbols.push_back(argument); return argument; } Function *newFunction(unsigned sourceLocation, const Name *name) { Function *function = new Function(translationUnit, sourceLocation, name); symbols.push_back(function); return function; } BaseClass *newBaseClass(unsigned sourceLocation, const Name *name) { BaseClass *baseClass = new BaseClass(translationUnit, sourceLocation, name); symbols.push_back(baseClass); return baseClass; } Block *newBlock(unsigned sourceLocation) { Block *block = new Block(translationUnit, sourceLocation); symbols.push_back(block); return block; } Class *newClass(unsigned sourceLocation, const Name *name) { Class *klass = new Class(translationUnit, sourceLocation, name); symbols.push_back(klass); return klass; } Namespace *newNamespace(unsigned sourceLocation, const Name *name) { Namespace *ns = new Namespace(translationUnit, sourceLocation, name); symbols.push_back(ns); return ns; } Template *newTemplate(unsigned sourceLocation, const Name *name) { Template *ns = new Template(translationUnit, sourceLocation, name); symbols.push_back(ns); return ns; } NamespaceAlias *newNamespaceAlias(unsigned sourceLocation, const Name *name) { NamespaceAlias *ns = new NamespaceAlias(translationUnit, sourceLocation, name); symbols.push_back(ns); return ns; } UsingNamespaceDirective *newUsingNamespaceDirective(unsigned sourceLocation, const Name *name) { UsingNamespaceDirective *u = new UsingNamespaceDirective(translationUnit, sourceLocation, name); symbols.push_back(u); return u; } ForwardClassDeclaration *newForwardClassDeclaration(unsigned sourceLocation, const Name *name) { ForwardClassDeclaration *c = new ForwardClassDeclaration(translationUnit, sourceLocation, name); symbols.push_back(c); return c; } QtPropertyDeclaration *newQtPropertyDeclaration(unsigned sourceLocation, const Name *name) { QtPropertyDeclaration *d = new QtPropertyDeclaration(translationUnit, sourceLocation, name); symbols.push_back(d); return d; } QtEnum *newQtEnum(unsigned sourceLocation, const Name *name) { QtEnum *d = new QtEnum(translationUnit, sourceLocation, name); symbols.push_back(d); return d; } ObjCBaseClass *newObjCBaseClass(unsigned sourceLocation, const Name *name) { ObjCBaseClass *c = new ObjCBaseClass(translationUnit, sourceLocation, name); symbols.push_back(c); return c; } ObjCBaseProtocol *newObjCBaseProtocol(unsigned sourceLocation, const Name *name) { ObjCBaseProtocol *p = new ObjCBaseProtocol(translationUnit, sourceLocation, name); symbols.push_back(p); return p; } ObjCClass *newObjCClass(unsigned sourceLocation, const Name *name) { ObjCClass *c = new ObjCClass(translationUnit, sourceLocation, name); symbols.push_back(c); return c; } ObjCForwardClassDeclaration *newObjCForwardClassDeclaration(unsigned sourceLocation, const Name *name) { ObjCForwardClassDeclaration *fwd = new ObjCForwardClassDeclaration(translationUnit, sourceLocation, name); symbols.push_back(fwd); return fwd; } ObjCProtocol *newObjCProtocol(unsigned sourceLocation, const Name *name) { ObjCProtocol *p = new ObjCProtocol(translationUnit, sourceLocation, name); symbols.push_back(p); return p; } ObjCForwardProtocolDeclaration *newObjCForwardProtocolDeclaration(unsigned sourceLocation, const Name *name) { ObjCForwardProtocolDeclaration *fwd = new ObjCForwardProtocolDeclaration(translationUnit, sourceLocation, name); symbols.push_back(fwd); return fwd; } ObjCMethod *newObjCMethod(unsigned sourceLocation, const Name *name) { ObjCMethod *method = new ObjCMethod(translationUnit, sourceLocation, name); symbols.push_back(method); return method; } ObjCPropertyDeclaration *newObjCPropertyDeclaration(unsigned sourceLocation, const Name *name) { ObjCPropertyDeclaration *decl = new ObjCPropertyDeclaration(translationUnit, sourceLocation, name); symbols.push_back(decl); return decl; } Enum *newEnum(unsigned sourceLocation, const Name *name) { Enum *e = new Enum(translationUnit, sourceLocation, name); symbols.push_back(e); return e; } UsingDeclaration *newUsingDeclaration(unsigned sourceLocation, const Name *name) { UsingDeclaration *u = new UsingDeclaration(translationUnit, sourceLocation, name); symbols.push_back(u); return u; } Control *control; TranslationUnit *translationUnit; DiagnosticClient *diagnosticClient; LiteralTable identifiers; LiteralTable stringLiterals; LiteralTable numericLiterals; // ### replace std::map with lookup tables. ASAP! // names Table anonymousNameIds; Table destructorNameIds; Table operatorNameIds; Table conversionNameIds; Table templateNameIds; Table qualifiedNameIds; Table selectorNameIds; // types VoidType voidType; Table integerTypes; Table floatTypes; Table pointerToMemberTypes; Table pointerTypes; Table referenceTypes; Table arrayTypes; Table namedTypes; // symbols std::vector symbols; const Identifier *deprecatedId; const Identifier *unavailableId; // ObjC context keywords: const Identifier *objcGetterId; const Identifier *objcSetterId; const Identifier *objcReadwriteId; const Identifier *objcReadonlyId; const Identifier *objcAssignId; const Identifier *objcRetainId; const Identifier *objcCopyId; const Identifier *objcNonatomicId; const Identifier *cpp11Override; const Identifier *cpp11Final; TopLevelDeclarationProcessor *processor; }; Control::Control() { d = new Data(this); d->deprecatedId = identifier("deprecated"); d->unavailableId = identifier("unavailable"); d->objcGetterId = identifier("getter"); d->objcSetterId = identifier("setter"); d->objcReadwriteId = identifier("readwrite"); d->objcReadonlyId = identifier("readonly"); d->objcAssignId = identifier("assign"); d->objcRetainId = identifier("retain"); d->objcCopyId = identifier("copy"); d->objcNonatomicId = identifier("nonatomic"); d->cpp11Override = identifier("override"); d->cpp11Final = identifier("final"); } Control::~Control() { delete d; } TranslationUnit *Control::translationUnit() const { return d->translationUnit; } TranslationUnit *Control::switchTranslationUnit(TranslationUnit *unit) { TranslationUnit *previousTranslationUnit = d->translationUnit; d->translationUnit = unit; return previousTranslationUnit; } DiagnosticClient *Control::diagnosticClient() const { return d->diagnosticClient; } void Control::setDiagnosticClient(DiagnosticClient *diagnosticClient) { d->diagnosticClient = diagnosticClient; } const AnonymousNameId *Control::anonymousNameId(unsigned classTokenIndex) { return d->findOrInsertAnonymousNameId(classTokenIndex); } const OperatorNameId *Control::findOperatorNameId(OperatorNameId::Kind operatorId) const { Table::const_iterator i = d->operatorNameIds.find(operatorId); if (i == d->operatorNameIds.end()) return nullptr; else return &*i; } const ConversionNameId *Control::findConversionNameId(const FullySpecifiedType &type) const { for (const ConversionNameId &id : d->conversionNameIds) { if (type.match(id.type())) return &id; } return nullptr; } const Identifier *Control::findIdentifier(const char *chars, int size) const { return d->identifiers.findLiteral(chars, size); } const Identifier *Control::identifier(const char *chars, int size) { return d->identifiers.findOrInsertLiteral(chars, size); } const Identifier *Control::identifier(const char *chars) { const int length = int(std::strlen(chars)); return identifier(chars, length); } Control::IdentifierIterator Control::firstIdentifier() const { return d->identifiers.begin(); } Control::IdentifierIterator Control::lastIdentifier() const { return d->identifiers.end(); } Control::StringLiteralIterator Control::firstStringLiteral() const { return d->stringLiterals.begin(); } Control::StringLiteralIterator Control::lastStringLiteral() const { return d->stringLiterals.end(); } Control::NumericLiteralIterator Control::firstNumericLiteral() const { return d->numericLiterals.begin(); } Control::NumericLiteralIterator Control::lastNumericLiteral() const { return d->numericLiterals.end(); } const StringLiteral *Control::stringLiteral(const char *chars, int size) { return d->stringLiterals.findOrInsertLiteral(chars, size); } const StringLiteral *Control::stringLiteral(const char *chars) { const int length = int(std::strlen(chars)); return stringLiteral(chars, length); } const NumericLiteral *Control::numericLiteral(const char *chars, int size) { return d->numericLiterals.findOrInsertLiteral(chars, size); } const NumericLiteral *Control::numericLiteral(const char *chars) { const int length = int(std::strlen(chars)); return numericLiteral(chars, length); } const TemplateNameId *Control::templateNameId(const Identifier *id, bool isSpecialization, const TemplateArgument *const args, int argv) { return d->findOrInsertTemplateNameId(id, isSpecialization, args, args + argv); } const DestructorNameId *Control::destructorNameId(const Name *name) { return d->findOrInsertDestructorNameId(name); } const OperatorNameId *Control::operatorNameId(OperatorNameId::Kind kind) { return d->findOrInsertOperatorNameId(kind); } const ConversionNameId *Control::conversionNameId(const FullySpecifiedType &type) { return d->findOrInsertConversionNameId(type); } const QualifiedNameId *Control::qualifiedNameId(const Name *base, const Name *name) { return d->findOrInsertQualifiedNameId(base, name); } const SelectorNameId *Control::selectorNameId(const Name *const *names, int nameCount, bool hasArguments) { return d->findOrInsertSelectorNameId(names, names + nameCount, hasArguments); } VoidType *Control::voidType() { return &d->voidType; } IntegerType *Control::integerType(int kind) { return d->findOrInsertIntegerType(kind); } FloatType *Control::floatType(int kind) { return d->findOrInsertFloatType(kind); } PointerToMemberType *Control::pointerToMemberType(const Name *memberName, const FullySpecifiedType &elementType) { return d->findOrInsertPointerToMemberType(memberName, elementType); } PointerType *Control::pointerType(const FullySpecifiedType &elementType) { return d->findOrInsertPointerType(elementType); } ReferenceType *Control::referenceType(const FullySpecifiedType &elementType, bool rvalueRef) { return d->findOrInsertReferenceType(elementType, rvalueRef); } ArrayType *Control::arrayType(const FullySpecifiedType &elementType, int size) { return d->findOrInsertArrayType(elementType, size); } NamedType *Control::namedType(const Name *name) { return d->findOrInsertNamedType(name); } Argument *Control::newArgument(int sourceLocation, const Name *name) { return d->newArgument(sourceLocation, name); } TypenameArgument *Control::newTypenameArgument(int sourceLocation, const Name *name) { return d->newTypenameArgument(sourceLocation, name); } Function *Control::newFunction(int sourceLocation, const Name *name) { return d->newFunction(sourceLocation, name); } Namespace *Control::newNamespace(int sourceLocation, const Name *name) { return d->newNamespace(sourceLocation, name); } Template *Control::newTemplate(int sourceLocation, const Name *name) { return d->newTemplate(sourceLocation, name); } NamespaceAlias *Control::newNamespaceAlias(int sourceLocation, const Name *name) { return d->newNamespaceAlias(sourceLocation, name); } BaseClass *Control::newBaseClass(int sourceLocation, const Name *name) { return d->newBaseClass(sourceLocation, name); } Class *Control::newClass(int sourceLocation, const Name *name) { return d->newClass(sourceLocation, name); } Enum *Control::newEnum(int sourceLocation, const Name *name) { return d->newEnum(sourceLocation, name); } Block *Control::newBlock(int sourceLocation) { return d->newBlock(sourceLocation); } Declaration *Control::newDeclaration(int sourceLocation, const Name *name) { return d->newDeclaration(sourceLocation, name); } EnumeratorDeclaration *Control::newEnumeratorDeclaration(int sourceLocation, const Name *name) { return d->newEnumeratorDeclaration(sourceLocation, name); } UsingNamespaceDirective *Control::newUsingNamespaceDirective(int sourceLocation, const Name *name) { return d->newUsingNamespaceDirective(sourceLocation, name); } UsingDeclaration *Control::newUsingDeclaration(int sourceLocation, const Name *name) { return d->newUsingDeclaration(sourceLocation, name); } ForwardClassDeclaration *Control::newForwardClassDeclaration(int sourceLocation, const Name *name) { return d->newForwardClassDeclaration(sourceLocation, name); } QtPropertyDeclaration *Control::newQtPropertyDeclaration(int sourceLocation, const Name *name) { return d->newQtPropertyDeclaration(sourceLocation, name); } QtEnum *Control::newQtEnum(int sourceLocation, const Name *name) { return d->newQtEnum(sourceLocation, name); } ObjCBaseClass *Control::newObjCBaseClass(int sourceLocation, const Name *name) { return d->newObjCBaseClass(sourceLocation, name); } ObjCBaseProtocol *Control::newObjCBaseProtocol(int sourceLocation, const Name *name) { return d->newObjCBaseProtocol(sourceLocation, name); } ObjCClass *Control::newObjCClass(int sourceLocation, const Name *name) { return d->newObjCClass(sourceLocation, name); } ObjCForwardClassDeclaration *Control::newObjCForwardClassDeclaration(int sourceLocation, const Name *name) { return d->newObjCForwardClassDeclaration(sourceLocation, name); } ObjCProtocol *Control::newObjCProtocol(int sourceLocation, const Name *name) { return d->newObjCProtocol(sourceLocation, name); } ObjCForwardProtocolDeclaration *Control::newObjCForwardProtocolDeclaration(int sourceLocation, const Name *name) { return d->newObjCForwardProtocolDeclaration(sourceLocation, name); } ObjCMethod *Control::newObjCMethod(int sourceLocation, const Name *name) { return d->newObjCMethod(sourceLocation, name); } ObjCPropertyDeclaration *Control::newObjCPropertyDeclaration(int sourceLocation, const Name *name) { return d->newObjCPropertyDeclaration(sourceLocation, name); } const Identifier *Control::deprecatedId() const { return d->deprecatedId; } const Identifier *Control::unavailableId() const { return d->unavailableId; } const Identifier *Control::objcGetterId() const { return d->objcGetterId; } const Identifier *Control::objcSetterId() const { return d->objcSetterId; } const Identifier *Control::objcReadwriteId() const { return d->objcReadwriteId; } const Identifier *Control::objcReadonlyId() const { return d->objcReadonlyId; } const Identifier *Control::objcAssignId() const { return d->objcAssignId; } const Identifier *Control::objcRetainId() const { return d->objcRetainId; } const Identifier *Control::objcCopyId() const { return d->objcCopyId; } const Identifier *Control::objcNonatomicId() const { return d->objcNonatomicId; } const Identifier *Control::cpp11Override() const { return d->cpp11Override; } const Identifier *Control::cpp11Final() const { return d->cpp11Final; } Symbol **Control::firstSymbol() const { if (d->symbols.empty()) return nullptr; return &*d->symbols.begin(); } Symbol **Control::lastSymbol() const { if (d->symbols.empty()) return nullptr; return &*d->symbols.begin() + d->symbols.size(); } int Control::symbolCount() const { return unsigned(d->symbols.size()); } bool Control::hasSymbol(Symbol *symbol) const { return std::find(d->symbols.begin(), d->symbols.end(), symbol) != d->symbols.end(); } TopLevelDeclarationProcessor *Control::topLevelDeclarationProcessor() const { return d->processor; } void Control::setTopLevelDeclarationProcessor(TopLevelDeclarationProcessor *processor) { d->processor = processor; } void Control::addSymbol(Symbol *symbol) { d->symbols.push_back(symbol); } const Name *Control::toName(const QList &names) { const Name *n = nullptr; for (int i = names.size() - 1; i >= 0; --i) { if (! n) n = names.at(i); else n = qualifiedNameId(names.at(i), n); } return n; }