// 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 "CoreTypes.h" #include "Literals.h" #include "Matcher.h" #include "Names.h" #include "Scope.h" #include "Symbols.h" #include "SymbolVisitor.h" #include "Templates.h" #include "TypeVisitor.h" #include using namespace CPlusPlus; UsingNamespaceDirective::UsingNamespaceDirective(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name) : Symbol(translationUnit, sourceLocation, name) { } UsingNamespaceDirective::UsingNamespaceDirective(Clone *clone, Subst *subst, UsingNamespaceDirective *original) : Symbol(clone, subst, original) { } UsingNamespaceDirective::~UsingNamespaceDirective() { } FullySpecifiedType UsingNamespaceDirective::type() const { return FullySpecifiedType(); } void UsingNamespaceDirective::visitSymbol0(SymbolVisitor *visitor) { visitor->visit(this); } NamespaceAlias::NamespaceAlias(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name) : Symbol(translationUnit, sourceLocation, name), _namespaceName(0) { } NamespaceAlias::NamespaceAlias(Clone *clone, Subst *subst, NamespaceAlias *original) : Symbol(clone, subst, original) , _namespaceName(clone->name(original->_namespaceName, subst)) { } NamespaceAlias::~NamespaceAlias() { } const Name *NamespaceAlias::namespaceName() const { return _namespaceName; } void NamespaceAlias::setNamespaceName(const Name *namespaceName) { _namespaceName = namespaceName; } FullySpecifiedType NamespaceAlias::type() const { return FullySpecifiedType(); } void NamespaceAlias::visitSymbol0(SymbolVisitor *visitor) { visitor->visit(this); } UsingDeclaration::UsingDeclaration(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name) : Symbol(translationUnit, sourceLocation, name) { } UsingDeclaration::UsingDeclaration(Clone *clone, Subst *subst, UsingDeclaration *original) : Symbol(clone, subst, original) { } UsingDeclaration::~UsingDeclaration() { } FullySpecifiedType UsingDeclaration::type() const { return FullySpecifiedType(); } void UsingDeclaration::visitSymbol0(SymbolVisitor *visitor) { visitor->visit(this); } Declaration::Declaration(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name) : Symbol(translationUnit, sourceLocation, name) , _initializer(0) { } Declaration::Declaration(Clone *clone, Subst *subst, Declaration *original) : Symbol(clone, subst, original) , _type(clone->type(original->_type, subst)) , _initializer(clone->stringLiteral(original->_initializer)) { const char* nameId = nullptr; const Name *theName = name(); if (!theName) return; if (const Identifier* identifier = theName->identifier()) nameId = identifier->chars(); else return; Class *enClass = original->enclosingClass(); const char* enClassNameId = nullptr; if (enClass && enClass->name() && enClass->name()->identifier()) { enClassNameId = enClass->name()->identifier()->chars(); } else { return; } if (!enClassNameId) return; Template *templSpec = enClass->enclosingTemplate(); const char* enNamespaceNameId = nullptr; if (templSpec) { if (Namespace* ns = templSpec->enclosingNamespace()) { if (ns->isInline()) ns = ns->enclosingNamespace(); if (ns->name() && ns->name()->identifier()) enNamespaceNameId =ns->name()->identifier()->chars(); } } if (!enNamespaceNameId || templSpec->templateParameterCount() < 1) return; const Name *firstTemplParamName = nullptr; if (const TypenameArgument *templParam = templSpec->templateParameterAt(0)->asTypenameArgument()) { firstTemplParamName = templParam->name(); } if (!firstTemplParamName) return; if (!subst) return; FullySpecifiedType newType; if (std::strcmp(enNamespaceNameId, "std") == 0 || std::strcmp(enNamespaceNameId, "__cxx11") == 0) { if (std::strcmp(enClassNameId, "unique_ptr") == 0) { if (std::strcmp(nameId, "pointer") == 0) { newType = clone->type(subst->apply(firstTemplParamName), 0); newType = FullySpecifiedType(clone->control()->pointerType(newType)); } } else if (std::strcmp(enClassNameId, "list") == 0 || std::strcmp(enClassNameId, "forward_list") == 0 || std::strcmp(enClassNameId, "vector") == 0 || std::strcmp(enClassNameId, "queue") == 0 || std::strcmp(enClassNameId, "deque") == 0 || std::strcmp(enClassNameId, "set") == 0 || std::strcmp(enClassNameId, "unordered_set") == 0 || std::strcmp(enClassNameId, "multiset") == 0 || std::strcmp(enClassNameId, "array") == 0) { if (std::strcmp(nameId, "reference") == 0 || std::strcmp(nameId, "const_reference") == 0) { newType = clone->type(subst->apply(firstTemplParamName), 0); } else if (std::strcmp(nameId, "iterator") == 0 || std::strcmp(nameId, "reverse_iterator") == 0 || std::strcmp(nameId, "const_reverse_iterator") == 0 || std::strcmp(nameId, "const_iterator") == 0) { newType = clone->type(subst->apply(firstTemplParamName), 0); newType = FullySpecifiedType(clone->control()->pointerType(newType)); } } else if (std::strcmp(enClassNameId, "_Hash") == 0 || std::strcmp(enClassNameId, "_Tree") == 0 ) { if (std::strcmp(nameId, "iterator") == 0 || std::strcmp(nameId, "reverse_iterator") == 0 || std::strcmp(nameId, "const_reverse_iterator") == 0 || std::strcmp(nameId, "const_iterator") == 0) { FullySpecifiedType clonedType = clone->type(subst->apply(firstTemplParamName), 0); if (NamedType *namedType = clonedType.type()->asNamedType()) { if (const TemplateNameId * templateNameId = namedType->name()->asTemplateNameId()) { if (templateNameId->templateArgumentCount()) { newType = clone->type(templateNameId->templateArgumentAt(0), 0); newType = FullySpecifiedType(clone->control()->pointerType(newType)); } } } } } } if (newType.isValid()) _type = newType; } Declaration::~Declaration() { } void Declaration::setType(const FullySpecifiedType &type) { _type = type; } void Declaration::setInitializer(const StringLiteral *initializer) { _initializer = initializer; } FullySpecifiedType Declaration::type() const { return _type; } const StringLiteral *Declaration::getInitializer() const { return _initializer; } void Declaration::visitSymbol0(SymbolVisitor *visitor) { visitor->visit(this); } EnumeratorDeclaration::EnumeratorDeclaration(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name) : Declaration(translationUnit, sourceLocation, name) , _constantValue(0) {} EnumeratorDeclaration::~EnumeratorDeclaration() {} const StringLiteral *EnumeratorDeclaration::constantValue() const { return _constantValue; } void EnumeratorDeclaration::setConstantValue(const StringLiteral *constantValue) { _constantValue = constantValue; } Argument::Argument(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name) : Symbol(translationUnit, sourceLocation, name), _initializer(0) { } Argument::Argument(Clone *clone, Subst *subst, Argument *original) : Symbol(clone, subst, original) , _initializer(clone->stringLiteral(original->_initializer)) , _type(clone->type(original->_type, subst)) { } Argument::~Argument() { } bool Argument::hasInitializer() const { return _initializer != 0; } const StringLiteral *Argument::initializer() const { return _initializer; } void Argument::setInitializer(const StringLiteral *initializer) { _initializer = initializer; } void Argument::setType(const FullySpecifiedType &type) { _type = type; } FullySpecifiedType Argument::type() const { return _type; } void Argument::visitSymbol0(SymbolVisitor *visitor) { visitor->visit(this); } TypenameArgument::TypenameArgument(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name) : Symbol(translationUnit, sourceLocation, name) , _isClassDeclarator(false) { } TypenameArgument::TypenameArgument(Clone *clone, Subst *subst, TypenameArgument *original) : Symbol(clone, subst, original) , _type(clone->type(original->_type, subst)) , _isClassDeclarator(original->_isClassDeclarator) { } TypenameArgument::~TypenameArgument() { } void TypenameArgument::setType(const FullySpecifiedType &type) { _type = type; } FullySpecifiedType TypenameArgument::type() const { return _type; } void TypenameArgument::visitSymbol0(SymbolVisitor *visitor) { visitor->visit(this); } Function::Function(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name) : Scope(translationUnit, sourceLocation, name), _flags(0) { } Function::Function(Clone *clone, Subst *subst, Function *original) : Scope(clone, subst, original) , _returnType(clone->type(original->_returnType, subst)) , _flags(original->_flags) { } Function::~Function() { } bool Function::isNormal() const { return f._methodKey == NormalMethod; } bool Function::isSignal() const { return f._methodKey == SignalMethod; } bool Function::isSlot() const { return f._methodKey == SlotMethod; } bool Function::isInvokable() const { return f._methodKey == InvokableMethod; } int Function::methodKey() const { return f._methodKey; } void Function::setMethodKey(int key) { f._methodKey = key; } bool Function::isSignatureEqualTo(const Function *other, Matcher *matcher) const { if (! other) return false; else if (isConst() != other->isConst()) return false; else if (isVolatile() != other->isVolatile()) return false; else if (! Matcher::match(unqualifiedName(), other->unqualifiedName(), matcher)) return false; const unsigned argc = argumentCount(); if (argc != other->argumentCount()) return false; for (unsigned i = 0; i < argc; ++i) { Symbol *l = argumentAt(i); Symbol *r = other->argumentAt(i); if (! l->type().match(r->type(), matcher)) { if (!l->type()->isReferenceType() && !l->type()->isPointerType() && !l->type()->isPointerToMemberType() && !r->type()->isReferenceType() && !r->type()->isPointerType() && !r->type()->isPointerToMemberType()) { FullySpecifiedType lType = l->type(); FullySpecifiedType rType = r->type(); lType.setConst(false); lType.setVolatile(false); rType.setConst(false); rType.setVolatile(false); if (lType.match(rType)) continue; } return false; } } return true; } void Function::accept0(TypeVisitor *visitor) { visitor->visit(this); } bool Function::match0(const Type *otherType, Matcher *matcher) const { if (const Function *otherTy = otherType->asFunctionType()) return matcher->match(this, otherTy); return false; } FullySpecifiedType Function::type() const { FullySpecifiedType ty(const_cast(this)); ty.setConst(isConst()); ty.setVolatile(isVolatile()); return ty; } FullySpecifiedType Function::returnType() const { return _returnType; } void Function::setReturnType(const FullySpecifiedType &returnType) { _returnType = returnType; } bool Function::hasReturnType() const { const FullySpecifiedType ty = returnType(); return ty.isValid() || ty.isSigned() || ty.isUnsigned(); } unsigned Function::argumentCount() const { const unsigned memCnt = memberCount(); if (memCnt > 0 && memberAt(0)->type()->isVoidType()) return 0; // Definitions with function-try-blocks will have more than a block, and // arguments with a lambda as default argument will also have more blocks. unsigned argc = 0; for (unsigned it = 0; it < memCnt; ++it) if (memberAt(it)->isArgument()) ++argc; return argc; } Symbol *Function::argumentAt(unsigned index) const { for (unsigned it = 0, eit = memberCount(); it < eit; ++it) { if (Argument *arg = memberAt(it)->asArgument()) { if (index == 0) return arg; else --index; } } return 0; } bool Function::hasArguments() const { unsigned argc = argumentCount(); return ! (argc == 0 || (argc == 1 && argumentAt(0)->type()->isVoidType())); } unsigned Function::minimumArgumentCount() const { unsigned index = 0; for (unsigned ei = argumentCount(); index < ei; ++index) { if (Argument *arg = argumentAt(index)->asArgument()) { if (arg->hasInitializer()) break; } } return index; } bool Function::isVirtual() const { return f._isVirtual; } void Function::setVirtual(bool isVirtual) { f._isVirtual = isVirtual; } bool Function::isOverride() const { return f._isOverride; } void Function::setOverride(bool isOverride) { f._isOverride = isOverride; } bool Function::isFinal() const { return f._isFinal; } void Function::setFinal(bool isFinal) { f._isFinal = isFinal; } bool Function::isVariadic() const { return f._isVariadic; } void Function::setVariadic(bool isVariadic) { f._isVariadic = isVariadic; } bool Function::isConst() const { return f._isConst; } void Function::setConst(bool isConst) { f._isConst = isConst; } bool Function::isVolatile() const { return f._isVolatile; } void Function::setVolatile(bool isVolatile) { f._isVolatile = isVolatile; } bool Function::isPureVirtual() const { return f._isPureVirtual; } void Function::setPureVirtual(bool isPureVirtual) { f._isPureVirtual = isPureVirtual; } Function::RefQualifier Function::refQualifier() const { return static_cast(f._refQualifier); } void Function::setRefQualifier(Function::RefQualifier refQualifier) { f._refQualifier = refQualifier; } bool Function::isAmbiguous() const { return f._isAmbiguous; } void Function::setAmbiguous(bool isAmbiguous) { f._isAmbiguous = isAmbiguous; } void Function::visitSymbol0(SymbolVisitor *visitor) { if (visitor->visit(this)) { for (unsigned i = 0; i < memberCount(); ++i) { visitSymbol(memberAt(i), visitor); } } } bool Function::maybeValidPrototype(unsigned actualArgumentCount) const { const unsigned argc = argumentCount(); unsigned minNumberArguments = 0; for (; minNumberArguments < argc; ++minNumberArguments) { Argument *arg = argumentAt(minNumberArguments)->asArgument(); if (! arg) return false; if (arg->hasInitializer()) break; } if (actualArgumentCount < minNumberArguments) { // not enough arguments. return false; } else if (!isVariadic() && actualArgumentCount > argc) { // too many arguments. return false; } return true; } Block::Block(TranslationUnit *translationUnit, unsigned sourceLocation) : Scope(translationUnit, sourceLocation, /*name = */ 0) { } Block::Block(Clone *clone, Subst *subst, Block *original) : Scope(clone, subst, original) { } Block::~Block() { } FullySpecifiedType Block::type() const { return FullySpecifiedType(); } void Block::visitSymbol0(SymbolVisitor *visitor) { if (visitor->visit(this)) { for (unsigned i = 0; i < memberCount(); ++i) { visitSymbol(memberAt(i), visitor); } } } Enum::Enum(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name) : Scope(translationUnit, sourceLocation, name) , _isScoped(false) { } Enum::Enum(Clone *clone, Subst *subst, Enum *original) : Scope(clone, subst, original) , _isScoped(original->isScoped()) { } Enum::~Enum() { } FullySpecifiedType Enum::type() const { return FullySpecifiedType(const_cast(this)); } bool Enum::isScoped() const { return _isScoped; } void Enum::setScoped(bool scoped) { _isScoped = scoped; } void Enum::accept0(TypeVisitor *visitor) { visitor->visit(this); } bool Enum::match0(const Type *otherType, Matcher *matcher) const { if (const Enum *otherTy = otherType->asEnumType()) return matcher->match(this, otherTy); return false; } void Enum::visitSymbol0(SymbolVisitor *visitor) { if (visitor->visit(this)) { for (unsigned i = 0; i < memberCount(); ++i) { visitSymbol(memberAt(i), visitor); } } } Template::Template(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name) : Scope(translationUnit, sourceLocation, name) { } Template::Template(Clone *clone, Subst *subst, Template *original) : Scope(clone, subst, original) { } Template::~Template() { } unsigned Template::templateParameterCount() const { if (declaration() != 0) return memberCount() - 1; return 0; } Symbol *Template::templateParameterAt(unsigned index) const { return memberAt(index); } Symbol *Template::declaration() const { if (isEmpty()) return 0; if (Symbol *s = memberAt(memberCount() - 1)) { if (s->isClass() || s->isForwardClassDeclaration() || s->isTemplate() || s->isFunction() || s->isDeclaration()) return s; } return 0; } FullySpecifiedType Template::type() const { return FullySpecifiedType(const_cast