| /******************************************************************************* |
| * Copyright (c) 2004, 2016 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Andrew Niefer (IBM Corporation) - initial API and implementation |
| * Markus Schorn (Wind River Systems) |
| * Andrew Ferguson (Symbian) |
| * Sergey Prigogin (Google) |
| * Thomas Corbat (IFS) |
| * Nathan Ridge |
| * Marc-Andre Laperle |
| * Anders Dahlberg (Ericsson) - bug 84144 |
| *******************************************************************************/ |
| package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; |
| |
| import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ALLCVQ; |
| import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE; |
| import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; |
| import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType; |
| import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateTypeUptoPointers; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Objects; |
| import java.util.Optional; |
| import java.util.Set; |
| import java.util.function.Predicate; |
| import java.util.stream.Stream; |
| |
| import org.eclipse.cdt.core.dom.ast.ASTGenericVisitor; |
| import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; |
| import org.eclipse.cdt.core.dom.ast.ASTVisitor; |
| import org.eclipse.cdt.core.dom.ast.DOMException; |
| import org.eclipse.cdt.core.dom.ast.EScopeKind; |
| import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator; |
| import org.eclipse.cdt.core.dom.ast.IASTArrayModifier; |
| import org.eclipse.cdt.core.dom.ast.IASTAttribute; |
| import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; |
| import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTDeclaration; |
| import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTDeclarator; |
| import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; |
| import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer; |
| import org.eclipse.cdt.core.dom.ast.IASTExpression; |
| import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; |
| import org.eclipse.cdt.core.dom.ast.IASTFieldReference; |
| import org.eclipse.cdt.core.dom.ast.IASTForStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; |
| import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; |
| import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; |
| import org.eclipse.cdt.core.dom.ast.IASTGotoStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTIdExpression; |
| import org.eclipse.cdt.core.dom.ast.IASTImplicitName; |
| import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner; |
| import org.eclipse.cdt.core.dom.ast.IASTInitializer; |
| import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; |
| import org.eclipse.cdt.core.dom.ast.IASTInitializerList; |
| import org.eclipse.cdt.core.dom.ast.IASTLabelStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; |
| import org.eclipse.cdt.core.dom.ast.IASTName; |
| import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTNode; |
| import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; |
| import org.eclipse.cdt.core.dom.ast.IASTPointer; |
| import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; |
| import org.eclipse.cdt.core.dom.ast.IASTProblem; |
| import org.eclipse.cdt.core.dom.ast.IASTProblemHolder; |
| import org.eclipse.cdt.core.dom.ast.IASTReturnStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; |
| import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator; |
| import org.eclipse.cdt.core.dom.ast.IASTStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; |
| import org.eclipse.cdt.core.dom.ast.IASTTypeId; |
| import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; |
| import org.eclipse.cdt.core.dom.ast.IArrayType; |
| import org.eclipse.cdt.core.dom.ast.IBasicType; |
| import org.eclipse.cdt.core.dom.ast.IBinding; |
| import org.eclipse.cdt.core.dom.ast.ICompositeType; |
| import org.eclipse.cdt.core.dom.ast.IEnumeration; |
| import org.eclipse.cdt.core.dom.ast.IEnumerator; |
| import org.eclipse.cdt.core.dom.ast.IField; |
| import org.eclipse.cdt.core.dom.ast.IFunction; |
| import org.eclipse.cdt.core.dom.ast.IFunctionType; |
| import org.eclipse.cdt.core.dom.ast.ILabel; |
| import org.eclipse.cdt.core.dom.ast.IParameter; |
| import org.eclipse.cdt.core.dom.ast.IProblemBinding; |
| import org.eclipse.cdt.core.dom.ast.IQualifierType; |
| import org.eclipse.cdt.core.dom.ast.IScope; |
| import org.eclipse.cdt.core.dom.ast.ISemanticProblem; |
| import org.eclipse.cdt.core.dom.ast.IType; |
| import org.eclipse.cdt.core.dom.ast.ITypedef; |
| import org.eclipse.cdt.core.dom.ast.IValue; |
| import org.eclipse.cdt.core.dom.ast.IVariable; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAliasDeclaration; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCapture; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldDesignator; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTIfStatement; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitCapture; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNameSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceAlias; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTPointerToMember; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateSpecialization; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplatedTypeTemplateParameter; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeTransformationSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTWhileStatement; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplate; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPBlockScope; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPDeferredFunction; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionScope; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceAlias; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPScope; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateScope; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; |
| import org.eclipse.cdt.core.dom.ast.util.ReturnStatementVisitor; |
| import org.eclipse.cdt.core.index.IIndex; |
| import org.eclipse.cdt.core.index.IIndexBinding; |
| import org.eclipse.cdt.core.parser.util.ArrayUtil; |
| import org.eclipse.cdt.core.parser.util.AttributeUtil; |
| import org.eclipse.cdt.core.parser.util.CharArrayUtils; |
| import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; |
| import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; |
| import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit; |
| import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope; |
| import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer; |
| import org.eclipse.cdt.internal.core.dom.parser.IntegralValue; |
| import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; |
| import org.eclipse.cdt.internal.core.dom.parser.ProblemType; |
| import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFieldReference; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFunctionCallExpression; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTUnaryExpression; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPAliasTemplate; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPArrayType; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplate; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassType; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClosureType; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructor; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructorTemplate; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumeration; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumerator; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPField; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFieldTemplate; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionTemplate; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPLabel; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethod; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodTemplate; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespace; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespaceAlias; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameter; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameterPackType; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPlaceholderType; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPlaceholderType.PlaceholderKind; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScope; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeArgument; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateTypeArgument; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTypedef; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnaryTypeTransformation; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownTypeScope; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariable; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariableTemplate; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; |
| |
| /** |
| * Collection of methods to extract information from a C++ translation unit. |
| */ |
| public class CPPVisitor extends ASTQueries { |
| public static final String BEGIN_STR = "begin"; //$NON-NLS-1$ |
| public static final char[] BEGIN = BEGIN_STR.toCharArray(); |
| public static final char[] END = "end".toCharArray(); //$NON-NLS-1$ |
| public static final String STD = "std"; //$NON-NLS-1$ |
| private static final char[] SIZE_T = "size_t".toCharArray(); //$NON-NLS-1$ |
| private static final char[] PTRDIFF_T = "ptrdiff_t".toCharArray(); //$NON-NLS-1$ |
| private static final char[] TYPE_INFO = "type_info".toCharArray(); //$NON-NLS-1$ |
| private static final char[] INITIALIZER_LIST = "initializer_list".toCharArray(); //$NON-NLS-1$ |
| private static final char[][] EMPTY_CHAR_ARRAY_ARRAY = {}; |
| private static final String STD_TUPLE_SIZE_STR = STD + "::tuple_size"; //$NON-NLS-1$ |
| private static final String STD_TUPLE_ELEMENT_STR = STD + "::tuple_element"; //$NON-NLS-1$ |
| private static final String VALUE_STR = "value"; //$NON-NLS-1$ |
| private static final String TYPE_STR = "type"; //$NON-NLS-1$ |
| public static final IASTInitializerClause[] NO_ARGS = {}; |
| |
| // Flags for createType(). |
| |
| // Attempt to resolve placeholders ('auto' and 'decltype(auto)'). |
| public static final int RESOLVE_PLACEHOLDERS = 0x1; |
| |
| // Given a function declarator, compute only the return type rather than |
| // the entire function type. |
| public static final int ONLY_RETURN_TYPE = 0x2; |
| |
| // Common combinations of flags. |
| public static final int DO_NOT_RESOLVE_PLACEHOLDERS = 0; |
| |
| // Thread-local set of declarators for which auto types are being created. |
| // Used to prevent infinite recursion while processing invalid self-referencing |
| // auto-type declarations. |
| private static final ThreadLocal<Set<IASTDeclarator>> autoTypeDeclarators = new ThreadLocal<Set<IASTDeclarator>>() { |
| @Override |
| protected Set<IASTDeclarator> initialValue() { |
| return new HashSet<>(); |
| } |
| }; |
| |
| public static final Predicate<IVariable> IS_STATIC_VARIABLE = IVariable::isStatic; |
| private static final Predicate<IVariable> HAS_INTEGRAL_TYPE = variable -> BuiltinOperators |
| .isIntegral(SemanticUtil.getUltimateTypeUptoPointers(variable.getType())); |
| private static final Predicate<IVariable> HAS_CONST_TYPE = field -> ExpressionTypes.isConst(field.getType()); |
| private static final Predicate<IBinding> IS_NAMED_VALUE = binding -> binding.getName().equals(VALUE_STR); |
| |
| /** |
| * Required until Java 9 Optional.stream() |
| */ |
| private static final <E> Stream<E> toStream(Optional<E> optional) { |
| return optional.map(Stream::of).orElse(Stream.empty()); |
| } |
| |
| public static IBinding createBinding(IASTName name) { |
| IASTNode parent = name.getParent(); |
| IBinding binding = null; |
| if (parent instanceof IASTNamedTypeSpecifier || parent instanceof ICPPASTBaseSpecifier |
| || parent instanceof ICPPASTConstructorChainInitializer |
| || (parent instanceof ICPPASTCapture && !(parent instanceof ICPPASTInitCapture)) |
| || name.getPropertyInParent() == ICPPASTNamespaceAlias.MAPPING_NAME) { |
| if (name.getLookupKey().length == 0) |
| return null; |
| |
| return CPPSemantics.resolveBinding(name); |
| } else if (parent instanceof ICPPASTQualifiedName) { |
| if (name.getLookupKey().length == 0) |
| return null; |
| |
| final ICPPASTQualifiedName qname = (ICPPASTQualifiedName) parent; |
| if (name != qname.getLastName()) |
| return CPPSemantics.resolveBinding(name); |
| |
| parent = parent.getParent(); |
| if (!declaresMemberInClassOrNamespace(qname)) { |
| binding = CPPSemantics.resolveBinding(name); |
| if (parent instanceof IASTCompositeTypeSpecifier) { |
| if (binding instanceof IIndexBinding) { |
| // Need to create an AST binding. |
| } else { |
| ASTInternal.addDefinition(binding, parent); |
| return binding; |
| } |
| } else { |
| return binding; |
| } |
| } |
| } else if (parent instanceof ICPPASTTemplateId) { |
| final ICPPASTTemplateId id = (ICPPASTTemplateId) parent; |
| if (CPPTemplates.isClassTemplate(id)) |
| return CPPSemantics.resolveBinding(name); |
| |
| // Function templates/instances/specializations must be resolved via the id. |
| id.resolveBinding(); |
| return name.getBinding(); |
| } |
| |
| if (parent instanceof IASTIdExpression) { |
| return resolveBinding(parent); |
| } else if (parent instanceof ICPPASTFieldReference) { |
| return resolveBinding(parent); |
| } else if (parent instanceof ICPPASTCompositeTypeSpecifier) { |
| return createBinding((ICPPASTCompositeTypeSpecifier) parent); |
| } else if (parent instanceof IASTDeclarator) { |
| return createBinding((IASTDeclarator) parent); |
| } else if (parent instanceof ICPPASTElaboratedTypeSpecifier) { |
| return createBinding((ICPPASTElaboratedTypeSpecifier) parent); |
| } else if (parent instanceof ICPPASTStructuredBindingDeclaration) { |
| return new CPPVariable(name); |
| } else if (parent instanceof IASTDeclaration) { |
| return createBinding((IASTDeclaration) parent); |
| } else if (parent instanceof ICPPASTEnumerationSpecifier) { |
| return createBinding((ICPPASTEnumerationSpecifier) parent); |
| } else if (parent instanceof IASTEnumerator) { |
| return createBinding((IASTEnumerator) parent); |
| } else if (parent instanceof IASTGotoStatement) { |
| return resolveBinding((IASTGotoStatement) parent); |
| } else if (parent instanceof IASTLabelStatement) { |
| return createBinding((IASTLabelStatement) parent); |
| } else if (parent instanceof ICPPASTTemplateParameter) { |
| return CPPTemplates.createBinding((ICPPASTTemplateParameter) parent); |
| } else if (parent instanceof ICPPASTFieldDesignator) { |
| binding = resolveBinding(parent); |
| } |
| |
| if (name.getLookupKey().length > 0) |
| return binding; |
| return null; |
| } |
| |
| private static boolean declaresMemberInClassOrNamespace(ICPPASTQualifiedName qname) { |
| ICPPASTNameSpecifier[] qualifier = qname.getQualifier(); |
| if (qualifier.length == 0) |
| return false; |
| |
| IASTNode parent = qname.getParent(); |
| IASTNode decl = null; |
| if (parent instanceof IASTCompositeTypeSpecifier) { |
| decl = parent.getParent(); |
| } else if (parent instanceof IASTDeclarator) { |
| decl = ASTQueries.findOutermostDeclarator((IASTDeclarator) parent).getParent(); |
| } |
| IScope inScope = null; |
| while (decl != null) { |
| ASTNodeProperty prop = decl.getPropertyInParent(); |
| if (prop == IASTCompositeTypeSpecifier.MEMBER_DECLARATION) { |
| inScope = ((ICPPASTCompositeTypeSpecifier) decl.getParent()).getScope(); |
| break; |
| } else if (prop == ICPPASTNamespaceDefinition.OWNED_DECLARATION) { |
| inScope = ((ICPPASTNamespaceDefinition) decl.getParent()).getScope(); |
| break; |
| } else if (prop == ICPPASTTemplateDeclaration.OWNED_DECLARATION) { |
| decl = decl.getParent(); |
| } else { |
| return false; |
| } |
| } |
| |
| if (inScope == null) |
| return false; |
| |
| IBinding pb = qualifier[qualifier.length - 1].resolvePreBinding(); |
| if (pb instanceof IProblemBinding) |
| return false; |
| |
| IScope scope = null; |
| if (pb instanceof IType) { |
| IType t = SemanticUtil.getNestedType((IType) pb, TDEF); |
| if (t instanceof ICPPClassType) { |
| scope = ((ICPPClassType) t).getCompositeScope(); |
| } |
| } else if (pb instanceof ICPPNamespace) { |
| scope = ((ICPPNamespace) pb).getNamespaceScope(); |
| } |
| |
| return scope == inScope; |
| } |
| |
| private static IBinding resolveBinding(IASTGotoStatement gotoStatement) { |
| return resolveLabel(gotoStatement.getName()); |
| } |
| |
| private static IBinding createBinding(IASTLabelStatement labelStatement) { |
| IASTName name = labelStatement.getName(); |
| ICPPFunctionScope functionScope = (ICPPFunctionScope) getContainingScope(name); |
| IBinding binding = functionScope.getBinding(name, false); |
| if (binding == null || !(binding instanceof ILabel)) { |
| binding = new CPPLabel(name); |
| ASTInternal.addName(functionScope, name); |
| } else { |
| ((CPPLabel) binding).setLabelStatement(name); |
| } |
| |
| return binding; |
| } |
| |
| private static IBinding createBinding(IASTEnumerator enumerator) { |
| ICPPScope scope = (ICPPScope) getContainingScope(enumerator); |
| IBinding enumtor; |
| enumtor = scope.getBinding(enumerator.getName(), false); |
| if (enumtor == null || !(enumtor instanceof IEnumerator)) { |
| enumtor = new CPPEnumerator(enumerator.getName()); |
| } |
| |
| return enumtor; |
| } |
| |
| private static IBinding createBinding(ICPPASTEnumerationSpecifier specifier) { |
| ICPPScope scope = (ICPPScope) getContainingScope(specifier); |
| final IASTName name = specifier.getName(); |
| IType fixedType = createEnumBaseType(specifier); |
| IBinding binding = scope.getBinding(name, false); |
| if (binding instanceof CPPEnumeration) { |
| CPPEnumeration e = (CPPEnumeration) binding; |
| if (name.equals(e.getDefinition())) { |
| return e; |
| } |
| if (e.isScoped() == specifier.isScoped()) { |
| IType ft2 = e.getFixedType(); |
| if (fixedType == ft2 || (fixedType != null && fixedType.isSameType(ft2))) { |
| if (specifier.isOpaque()) { |
| e.addDeclaration(name); |
| } else if (e.getDefinition() == null) { |
| e.addDefinition(name); |
| } else { |
| return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDEFINITION); |
| } |
| return e; |
| } |
| } |
| return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION); |
| } |
| // [dcl.enum] 7.2-5 |
| // "The underlying type can be explicitly specified using enum-base; |
| // if not explicitly specified, the underlying type of a scoped |
| // enumeration type is int." |
| if (fixedType == null && specifier.isScoped()) { |
| fixedType = CPPBasicType.INT; |
| } |
| return new CPPEnumeration(specifier, fixedType); |
| } |
| |
| private static IType createEnumBaseType(ICPPASTEnumerationSpecifier specifier) { |
| ICPPASTDeclSpecifier declspec = specifier.getBaseType(); |
| if (declspec != null) { |
| IType type = createType(declspec); |
| return SemanticUtil.getNestedType(type, ALLCVQ); |
| } |
| if (specifier.isScoped()) { |
| return CPPSemantics.INT_TYPE; |
| } |
| return null; |
| } |
| |
| private static IBinding createBinding(final ICPPASTElaboratedTypeSpecifier elabType) { |
| final IASTNode parent = elabType.getParent(); |
| IBinding binding = null; |
| boolean mustBeSimple = true; |
| boolean isFriend = false; |
| boolean qualified = false; |
| IASTName name = elabType.getName(); |
| if (name instanceof ICPPASTQualifiedName) { |
| qualified = true; |
| name = name.getLastName(); |
| } |
| if (parent instanceof IASTSimpleDeclaration) { |
| IASTSimpleDeclaration simpleDeclaration = (IASTSimpleDeclaration) parent; |
| ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) simpleDeclaration.getDeclSpecifier(); |
| IASTDeclarator[] dtors = simpleDeclaration.getDeclarators(); |
| isFriend = declSpec.isFriend() && dtors.length == 0; |
| if (dtors.length != 0 || isFriend) { |
| binding = CPPSemantics.resolveBinding(name); |
| mustBeSimple = !isFriend; |
| } else { |
| mustBeSimple = false; |
| } |
| } else if (parent instanceof IASTParameterDeclaration || parent instanceof IASTDeclaration |
| || parent instanceof IASTTypeId) { |
| binding = CPPSemantics.resolveBinding(elabType.getName()); |
| } |
| if (binding instanceof IIndexBinding && binding instanceof ICPPClassType) { |
| binding = (ICPPClassType) SemanticUtil.mapToAST((ICPPClassType) binding); |
| ASTInternal.addDeclaration(binding, elabType); |
| } |
| |
| if (binding != null && (!(binding instanceof IProblemBinding) |
| || ((IProblemBinding) binding).getID() != IProblemBinding.SEMANTIC_NAME_NOT_FOUND)) { |
| return binding; |
| } |
| |
| // 7.1.5.3-2 ... If name lookup does not find a declaration for the name, the elaborated-type-specifier is ill-formed |
| // unless it is of the simple form class-key identifier |
| if (mustBeSimple && (elabType.getName() instanceof ICPPASTQualifiedName |
| || elabType.getKind() == IASTElaboratedTypeSpecifier.k_enum)) { |
| return binding; |
| } |
| |
| try { |
| ICPPASTTemplateDeclaration templateDecl = CPPTemplates.getTemplateDeclaration(name); |
| ICPPScope scope = (ICPPScope) getContainingScope(name); |
| while (scope instanceof ICPPTemplateScope) { |
| scope = (ICPPScope) scope.getParent(); |
| } |
| |
| if (mustBeSimple) { |
| // 3.3.1-5 ... the identifier is declared in the smallest non-class non-function-prototype |
| // scope that contains the declaration. |
| while (scope instanceof ICPPClassScope || scope instanceof ICPPFunctionScope) { |
| scope = CPPSemantics.getParentScope(scope, elabType.getTranslationUnit()); |
| } |
| } |
| if (scope instanceof ICPPClassScope && isFriend && !qualified) { |
| while (scope instanceof ICPPClassScope) { |
| scope = CPPSemantics.getParentScope(scope, elabType.getTranslationUnit()); |
| } |
| } |
| if (scope != null) { |
| binding = scope.getBinding(elabType.getName(), false); |
| if (binding instanceof ICPPUsingDeclaration) { |
| IBinding[] expanded = ((ICPPUsingDeclaration) binding).getDelegates(); |
| if (expanded.length == 1 && expanded[0] instanceof IType) { |
| binding = expanded[0]; |
| } |
| } |
| } |
| if (binding instanceof ICPPInternalBinding) { |
| if (!name.isActive()) |
| return binding; |
| |
| if (binding instanceof ICPPClassType) { |
| ICPPInternalBinding internalBinding = (ICPPInternalBinding) binding; |
| if (templateParametersMatch((ICPPClassType) binding, templateDecl)) { |
| internalBinding.addDeclaration(elabType); |
| return binding; |
| } |
| |
| if (CPPSemantics.declaredBefore(internalBinding, name, false)) { |
| return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION); |
| } |
| markRedeclaration(internalBinding); |
| } |
| } |
| |
| // Create a binding. |
| if (elabType.getKind() != IASTElaboratedTypeSpecifier.k_enum) { |
| if (templateDecl != null) { |
| binding = new CPPClassTemplate(name); |
| } else { |
| binding = new CPPClassType(name, binding); |
| } |
| // Name may live in a different scope, so make sure to add it to the owner scope as well. |
| // [namespace.memdef] p3: |
| // "If a friend declaration in a non-local class first declares a |
| // class, function, class template or function template the friend |
| // is a member of the innermost enclosing namespace. The friend |
| // declaration does not by itself make the name visible to |
| // unqualified lookup or qualified lookup." |
| boolean visibleToAdlOnly = isFriend; |
| ASTInternal.addName(scope, elabType.getName(), visibleToAdlOnly); |
| } |
| } catch (DOMException e) { |
| binding = e.getProblem(); |
| } |
| |
| return binding; |
| } |
| |
| /** |
| * Checks if the given name is the name of a friend declaration. |
| * |
| * @param name the name to check |
| * @return {@code true} if {@code name} is the name of a friend declaration |
| */ |
| public static boolean isNameOfFriendDeclaration(IASTNode name) { |
| if (name.getPropertyInParent() == ICPPASTQualifiedName.SEGMENT_NAME) { |
| ICPPASTQualifiedName qName = (ICPPASTQualifiedName) name.getParent(); |
| if (name != qName.getLastName()) |
| return false; |
| name = qName; |
| } |
| if (name.getPropertyInParent() != ICPPASTElaboratedTypeSpecifier.TYPE_NAME) |
| return false; |
| ICPPASTElaboratedTypeSpecifier typeSpec = (ICPPASTElaboratedTypeSpecifier) name.getParent(); |
| if (typeSpec.getPropertyInParent() != IASTSimpleDeclaration.DECL_SPECIFIER) |
| return false; |
| IASTSimpleDeclaration declaration = (IASTSimpleDeclaration) typeSpec.getParent(); |
| ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) declaration.getDeclSpecifier(); |
| return declSpec.isFriend() && declaration.getDeclarators().length == 0; |
| } |
| |
| public static void markRedeclaration(final ICPPInternalBinding ib) { |
| // Mark the other declarations as problem and create the binding |
| final IASTNode[] decls = ib.getDeclarations(); |
| if (decls != null) { |
| for (IASTNode decl : decls) { |
| if (decl instanceof IASTName) { |
| final IASTName n = (IASTName) decl; |
| n.setBinding(new ProblemBinding(n, IProblemBinding.SEMANTIC_INVALID_REDECLARATION)); |
| } |
| } |
| } |
| IASTNode decl = ib.getDefinition(); |
| if (decl instanceof IASTName) { |
| final IASTName n = (IASTName) decl; |
| n.setBinding(new ProblemBinding(n, IProblemBinding.SEMANTIC_INVALID_REDEFINITION)); |
| } |
| } |
| |
| /** |
| * Tests whether a class binding matches the template parameters of another declaration |
| */ |
| private static boolean templateParametersMatch(ICPPClassType binding, ICPPASTTemplateDeclaration templateDecl) { |
| final boolean isTemplate = binding instanceof ICPPClassTemplate; |
| if (templateDecl == null) |
| return !isTemplate; |
| if (!isTemplate) |
| return false; |
| |
| ICPPTemplateParameter[] pars1 = ((ICPPClassTemplate) binding).getTemplateParameters(); |
| ICPPASTTemplateParameter[] pars2 = templateDecl.getTemplateParameters(); |
| |
| int i = 0; |
| for (ICPPASTTemplateParameter p2 : pars2) { |
| if (i >= pars1.length) |
| return true; |
| |
| if (!CPPSemantics.isSameTemplateParameter(pars1[i++], p2)) |
| return false; |
| } |
| return true; |
| } |
| |
| private static IBinding createBinding(ICPPASTCompositeTypeSpecifier compType) { |
| IASTName name = compType.getName().getLastName(); |
| if (name instanceof ICPPASTTemplateId) |
| return CPPTemplates.createBinding((ICPPASTTemplateId) name); |
| |
| ICPPScope scope = (ICPPScope) getContainingScope(name); |
| try { |
| while (scope instanceof ICPPTemplateScope) { |
| scope = (ICPPScope) scope.getParent(); |
| } |
| } catch (DOMException e) { |
| return e.getProblem(); |
| } |
| |
| // Can't lookup anonymous names. |
| IBinding binding = null; |
| ICPPASTTemplateDeclaration templateDecl = CPPTemplates.getTemplateDeclaration(name); |
| if (name.getLookupKey().length > 0 && scope != null) { |
| binding = scope.getBinding(name, false); |
| |
| if (binding instanceof ICPPInternalBinding && binding instanceof ICPPClassType && name.isActive()) { |
| ICPPInternalBinding internalBinding = (ICPPInternalBinding) binding; |
| if (internalBinding.getDefinition() == null |
| && templateParametersMatch((ICPPClassType) binding, templateDecl)) { |
| ASTInternal.addDefinition(internalBinding, compType); |
| return binding; |
| } |
| if (CPPSemantics.declaredBefore(internalBinding, name, false)) { |
| return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDEFINITION); |
| } |
| markRedeclaration(internalBinding); |
| } |
| } |
| if (templateDecl != null) |
| return new CPPClassTemplate(name); |
| |
| return new CPPClassType(name, binding); |
| } |
| |
| private static IBinding createBinding(IASTDeclaration declaration) { |
| if (declaration instanceof ICPPASTNamespaceDefinition) { |
| ICPPASTNamespaceDefinition namespaceDef = (ICPPASTNamespaceDefinition) declaration; |
| ICPPScope scope = (ICPPScope) getContainingScope(namespaceDef); |
| IBinding binding; |
| binding = scope.getBinding(namespaceDef.getName(), false); |
| if (!(binding instanceof ICPPInternalBinding) || binding instanceof IProblemBinding |
| || !(binding instanceof ICPPNamespace)) { |
| binding = new CPPNamespace(namespaceDef); |
| } |
| return binding; |
| } else if (declaration instanceof ICPPASTUsingDirective) { |
| return CPPSemantics.resolveBinding(((ICPPASTUsingDirective) declaration).getQualifiedName()); |
| } else if (declaration instanceof ICPPASTNamespaceAlias) { |
| ICPPASTNamespaceAlias alias = (ICPPASTNamespaceAlias) declaration; |
| ICPPScope scope = (ICPPScope) getContainingScope(declaration); |
| IBinding binding; |
| binding = scope.getBinding(alias.getAlias(), false); |
| if (!(binding instanceof ICPPInternalBinding)) { |
| IBinding namespace = alias.getMappingName().resolveBinding(); |
| if (namespace instanceof IProblemBinding) { |
| IProblemBinding problem = (IProblemBinding) namespace; |
| namespace = new CPPNamespace.CPPNamespaceProblem(problem.getASTNode(), problem.getID(), |
| alias.getMappingName().toCharArray()); |
| } |
| if (namespace instanceof ICPPNamespace) { |
| binding = new CPPNamespaceAlias(alias.getAlias(), (ICPPNamespace) namespace); |
| } else { |
| binding = new ProblemBinding(alias.getAlias(), IProblemBinding.SEMANTIC_NAME_NOT_FOUND); |
| } |
| } |
| return binding; |
| } else if (declaration instanceof ICPPASTAliasDeclaration) { |
| ICPPASTAliasDeclaration alias = (ICPPASTAliasDeclaration) declaration; |
| ICPPScope scope = (ICPPScope) getContainingScope(declaration); |
| IBinding binding = scope.getBinding(alias.getAlias(), false); |
| if (!(binding instanceof ICPPInternalBinding)) { |
| IType type = createType(alias.getMappingTypeId()); |
| if (type instanceof IProblemBinding) { |
| IProblemBinding problem = (IProblemBinding) type; |
| type = new CPPClassType.CPPClassTypeProblem(problem.getASTNode(), problem.getID(), |
| alias.getMappingTypeId().getAbstractDeclarator().getName().toCharArray()); |
| } |
| if (type != null) { |
| if (alias.getParent() instanceof ICPPASTTemplateDeclaration) { |
| binding = new CPPAliasTemplate(alias.getAlias(), type); |
| } else { |
| CPPTypedef typedef = new CPPTypedef(alias.getAlias()); |
| typedef.setType(type); |
| binding = typedef; |
| } |
| } else { |
| binding = new ProblemBinding(alias.getAlias(), IProblemBinding.SEMANTIC_NAME_NOT_FOUND); |
| } |
| } |
| return binding; |
| } |
| return null; |
| } |
| |
| private static int findParameterIndex(IASTParameterDeclaration param, IASTParameterDeclaration[] params) { |
| int i = 0; |
| for (; i < params.length; i++) { |
| if (params[i] == param) |
| return i; |
| } |
| return -1; |
| } |
| |
| private static IBinding createBinding(IASTDeclarator declarator) { |
| IASTNode parent = findOutermostDeclarator(declarator).getParent(); |
| |
| if (parent instanceof ICPPASTInitCapture) { |
| return new CPPVariable(declarator.getName()); |
| } |
| |
| declarator = findInnermostDeclarator(declarator); |
| |
| final IASTDeclarator typeRelevantDtor = findTypeRelevantDeclarator(declarator); |
| |
| IASTName name = declarator.getName().getLastName(); |
| |
| // In case the binding was created starting from another name within the declarator. |
| IBinding candidate = name.getBinding(); |
| if (candidate != null) { |
| return candidate; |
| } |
| |
| // Function type. |
| if (parent instanceof IASTTypeId) |
| return CPPSemantics.resolveBinding(name); |
| |
| // Function type for non-type template parameter. |
| ASTNodeProperty prop = parent.getPropertyInParent(); |
| if (prop == ICPPASTTemplateDeclaration.PARAMETER || prop == ICPPASTTemplatedTypeTemplateParameter.PARAMETER) { |
| return CPPTemplates.createBinding((ICPPASTTemplateParameter) parent); |
| } |
| |
| // Explicit instantiations. |
| if (prop == ICPPASTExplicitTemplateInstantiation.OWNED_DECLARATION) |
| return CPPSemantics.resolveBinding(name); |
| |
| // Explicit specializations. |
| ICPPASTTemplateDeclaration tmplDecl = CPPTemplates.getTemplateDeclaration(name); |
| if (tmplDecl instanceof ICPPASTTemplateSpecialization) { |
| IBinding b = CPPSemantics.resolveBinding(name); |
| if (parent instanceof ICPPASTFunctionDefinition) { |
| ASTInternal.addDefinition(b, name); |
| } else { |
| ASTInternal.addDeclaration(b, name); |
| } |
| return b; |
| } |
| |
| // Parameter declarations. |
| if (parent instanceof ICPPASTParameterDeclaration) { |
| ICPPASTParameterDeclaration param = (ICPPASTParameterDeclaration) parent; |
| parent = param.getParent(); |
| if (parent instanceof IASTStandardFunctionDeclarator) { |
| IASTStandardFunctionDeclarator fdtor = (IASTStandardFunctionDeclarator) param.getParent(); |
| // Create parameter bindings only if the declarator declares a function. |
| if (findTypeRelevantDeclarator(fdtor) != fdtor) |
| return null; |
| |
| final IASTNode dtorParent = findOutermostDeclarator(fdtor).getParent(); |
| if (dtorParent instanceof ICPPASTLambdaExpression) { |
| CPPClosureType closure = (CPPClosureType) ((ICPPASTLambdaExpression) dtorParent) |
| .getExpressionType(); |
| ICPPParameter[] paramBindings = closure.getParameters(); |
| int index = findParameterIndex(param, fdtor.getParameters()); |
| if (index >= 0 && index < paramBindings.length) { |
| return paramBindings[index]; |
| } |
| } |
| |
| if (dtorParent instanceof IASTDeclaration) { |
| int index = findParameterIndex(param, fdtor.getParameters()); |
| return new CPPParameter(name, index); |
| } |
| return null; |
| } else if (parent instanceof ICPPASTTemplateDeclaration) { |
| return CPPTemplates.createBinding(param); |
| } |
| return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_TYPE); |
| } |
| |
| // Function declaration/definition. |
| IBinding binding = null; |
| final boolean template = tmplDecl != null; |
| boolean isFriendDecl = false; |
| ICPPScope scope = (ICPPScope) getContainingNonTemplateScope(name); |
| if (scope instanceof ICPPClassScope) { |
| isFriendDecl = isFriendDeclaration(parent); |
| if (isFriendDecl) { |
| try { |
| while (scope.getKind() == EScopeKind.eClassType) { |
| scope = CPPSemantics.getParentScope(scope, name.getTranslationUnit()); |
| } |
| } catch (DOMException e1) { |
| } |
| } |
| } |
| boolean forceResolve = isFriendDecl && name instanceof ICPPASTTemplateId; |
| if (name.getLookupKey().length != 0 && scope != null) { |
| binding = scope.getBinding(name, forceResolve); |
| } |
| |
| boolean isFunction = false; |
| if (parent instanceof ICPPASTFunctionDefinition) { |
| isFunction = true; |
| } else if (parent instanceof IASTSimpleDeclaration) { |
| IASTSimpleDeclaration simpleDecl = (IASTSimpleDeclaration) parent; |
| if (simpleDecl.getDeclSpecifier().getStorageClass() == IASTDeclSpecifier.sc_typedef) { |
| // Typedef declaration. |
| if (binding instanceof ICPPInternalBinding && binding instanceof ITypedef && name.isActive()) { |
| IType t1 = ((ITypedef) binding).getType(); |
| IType t2 = createType(declarator); |
| if (t1 != null && t2 != null && t1.isSameType(t2)) { |
| ASTInternal.addDeclaration(binding, name); |
| return binding; |
| } |
| return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION); |
| } |
| // If we don't resolve the target type first, we get a problem binding in case |
| // the typedef redeclares the target type, otherwise it is safer to defer |
| // the resolution of the target type. |
| IType targetType = createType(declarator); |
| CPPTypedef td = new CPPTypedef(name); |
| td.setType(targetType); |
| binding = td; |
| } else if (typeRelevantDtor instanceof IASTFunctionDeclarator) { |
| // Function declaration via function declarator. |
| isFunction = true; |
| } else { |
| // Looks like a variable declaration. |
| IType t1 = createType(declarator); |
| if (SemanticUtil.getNestedType(t1, TDEF) instanceof IFunctionType) { |
| // Function declaration via a typedef for a function type |
| isFunction = true; |
| } else if (binding instanceof IParameter) { |
| // Variable declaration redeclaring a parameter. |
| binding = new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION); |
| } else { |
| // Variable declaration. |
| IType t2 = null; |
| if (binding != null && binding instanceof IVariable && !(binding instanceof IIndexBinding)) { |
| t2 = ((IVariable) binding).getType(); |
| } |
| if (t1 != null && t2 != null) { |
| if (areArraysOfTheSameElementType(t1, t2) || t1.isSameType(t2)) { |
| ASTInternal.addDeclaration(binding, name); |
| } else { |
| binding = new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION); |
| } |
| } else if (simpleDecl.getParent() instanceof ICPPASTCompositeTypeSpecifier) { |
| binding = new CPPField(name); |
| } else if (template) { |
| if (simpleDecl.getParent().getParent() instanceof ICPPASTCompositeTypeSpecifier) { |
| binding = new CPPFieldTemplate(name); |
| } else { |
| binding = new CPPVariableTemplate(name); |
| } |
| } else { |
| binding = new CPPVariable(name); |
| } |
| } |
| } |
| } |
| |
| if (isFunction) { |
| if (binding instanceof ICPPInternalBinding && binding instanceof ICPPFunction && name.isActive()) { |
| ICPPFunction function = (ICPPFunction) binding; |
| boolean sameFunction = CPPSemantics.isSameFunction(function, typeRelevantDtor) |
| || function instanceof ICPPDeferredFunction; |
| if (function.getOwner() instanceof ICPPClassType) { |
| // Don't consider a function brought into scope from a base class scope |
| // to be the same as a function declared in a derived class scope. |
| IScope bindingScope = ((ICPPClassType) function.getOwner()).getCompositeScope(); |
| if (bindingScope == null || !bindingScope.equals(scope)) { |
| sameFunction = false; |
| } |
| } |
| if (sameFunction) { |
| binding = CPPSemantics.checkDeclSpecifier(binding, name, parent); |
| if (binding instanceof IProblemBinding) |
| return binding; |
| |
| ICPPInternalBinding internal = (ICPPInternalBinding) function; |
| if (parent instanceof IASTSimpleDeclaration) { |
| ASTInternal.addDeclaration(internal, name); |
| } else if (internal.getDefinition() == null) { |
| ASTInternal.addDefinition(internal, name); |
| } else { |
| IASTNode def = internal.getDefinition(); |
| if (def instanceof IASTDeclarator) |
| def = ((IASTDeclarator) def).getName(); |
| if (def != name) { |
| return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDEFINITION); |
| } |
| } |
| |
| return function; |
| } |
| } |
| |
| if (scope instanceof ICPPClassScope) { |
| if (isConstructor(scope, typeRelevantDtor)) { |
| binding = template ? (ICPPConstructor) new CPPConstructorTemplate(name) |
| : new CPPConstructor((ICPPASTFunctionDeclarator) typeRelevantDtor); |
| } else { |
| binding = template ? (ICPPMethod) new CPPMethodTemplate(name) : new CPPMethod(typeRelevantDtor); |
| } |
| } else { |
| binding = template ? (ICPPFunction) new CPPFunctionTemplate(name) : new CPPFunction(typeRelevantDtor); |
| } |
| binding = CPPSemantics.checkDeclSpecifier(binding, name, parent); |
| if (isFriendDecl && scope instanceof IASTInternalScope) { |
| ((IASTInternalScope) scope).addBinding(binding); |
| } |
| } |
| |
| return binding; |
| } |
| |
| public static boolean isFriendDeclaration(IASTNode decl) { |
| IASTDeclSpecifier declSpec; |
| if (decl instanceof IASTSimpleDeclaration) { |
| declSpec = ((IASTSimpleDeclaration) decl).getDeclSpecifier(); |
| } else if (decl instanceof IASTFunctionDefinition) { |
| declSpec = ((IASTFunctionDefinition) decl).getDeclSpecifier(); |
| } else { |
| return false; |
| } |
| return declSpec instanceof ICPPASTDeclSpecifier && ((ICPPASTDeclSpecifier) declSpec).isFriend(); |
| } |
| |
| public static boolean isConstructor(IScope containingScope, IASTDeclarator declarator) { |
| if (containingScope instanceof ICPPClassScope && isConstructorDtor(declarator)) { |
| ICPPClassType classType = ((ICPPClassScope) containingScope).getClassType(); |
| final char[] dtorName = findInnermostDeclarator(declarator).getName().getLookupKey(); |
| return CharArrayUtils.equals(dtorName, classType.getNameCharArray()); |
| } |
| return false; |
| } |
| |
| public static boolean isConstructorDeclaration(IASTName name) { |
| if (name == null) |
| return false; |
| final ASTNodeProperty propertyInParent = name.getPropertyInParent(); |
| if (propertyInParent == null) |
| return false; |
| IASTNode parent = name.getParent(); |
| if (parent instanceof ICPPASTTemplateId) { |
| name = (IASTName) parent; |
| parent = name.getParent(); |
| } |
| if (parent instanceof ICPPASTQualifiedName) { |
| if (((ICPPASTQualifiedName) parent).getLastName() != name) |
| return false; |
| name = (IASTName) parent; |
| parent = name.getParent(); |
| } |
| if (parent instanceof IASTDeclarator) { |
| if (isConstructorDtor((IASTDeclarator) parent)) { |
| if (name instanceof ICPPASTQualifiedName) { |
| ICPPASTNameSpecifier[] qualifier = ((ICPPASTQualifiedName) name).getQualifier(); |
| if (qualifier.length >= 1) { |
| IBinding b = qualifier[qualifier.length - 1].resolvePreBinding(); |
| if (b instanceof IType) { |
| IType classType = getNestedType((IType) b, TDEF); |
| if (classType instanceof ICPPClassType) { |
| final char[] dtorName = name.getLastName().getLookupKey(); |
| final char[] className = ((ICPPClassType) classType).getNameCharArray(); |
| return CharArrayUtils.equals(dtorName, className); |
| } |
| } |
| } |
| return false; |
| } |
| while (parent != null) { |
| if (parent instanceof ICPPASTCompositeTypeSpecifier) { |
| final char[] className = ((ICPPASTCompositeTypeSpecifier) parent).getName().getLastName() |
| .getLookupKey(); |
| final char[] dtorName = name.getLookupKey(); |
| return CharArrayUtils.equals(dtorName, className); |
| } |
| parent = parent.getParent(); |
| } |
| } |
| } |
| return false; |
| } |
| |
| private static boolean isConstructorDtor(IASTDeclarator declarator) { |
| if (declarator == null || !(declarator instanceof IASTFunctionDeclarator)) |
| return false; |
| |
| IASTDeclSpecifier declSpec = null; |
| IASTNode parent = findOutermostDeclarator(declarator).getParent(); |
| if (parent instanceof IASTSimpleDeclaration) { |
| declSpec = ((IASTSimpleDeclaration) parent).getDeclSpecifier(); |
| } else if (parent instanceof IASTFunctionDefinition) { |
| declSpec = ((IASTFunctionDefinition) parent).getDeclSpecifier(); |
| } |
| if (declSpec != null && declSpec instanceof IASTSimpleDeclSpecifier) { |
| return (((IASTSimpleDeclSpecifier) declSpec).getType() == IASTSimpleDeclSpecifier.t_unspecified); |
| } |
| |
| return false; |
| } |
| |
| public static boolean isLastNameInUsingDeclaration(IASTName name) { |
| IASTNode parent = name.getParent(); |
| return parent instanceof ICPPASTQualifiedName && ((ICPPASTQualifiedName) parent).getLastName() == name |
| && parent.getParent() instanceof ICPPASTUsingDeclaration; |
| } |
| |
| public static IScope getContainingNonTemplateScope(final IASTNode inputNode) { |
| IScope scope = getContainingScope(inputNode); |
| while (scope instanceof ICPPTemplateScope) { |
| scope = getContainingScope(((ICPPTemplateScope) scope).getTemplateDeclaration()); |
| } |
| return scope; |
| } |
| |
| public static IScope getContainingScope(final IASTNode inputNode) { |
| if (inputNode == null || inputNode instanceof IASTTranslationUnit) |
| return null; |
| IASTNode node = inputNode; |
| while (node != null) { |
| if (node instanceof IASTName && !(node instanceof ICPPASTQualifiedName)) { |
| return getContainingScope((IASTName) node); |
| } |
| if (node instanceof IASTDeclaration) { |
| IASTNode parent = node.getParent(); |
| if (parent instanceof IASTTranslationUnit) { |
| return ((IASTTranslationUnit) parent).getScope(); |
| } else if (parent instanceof IASTDeclarationStatement) { |
| return getContainingScope((IASTStatement) parent); |
| } else if (parent instanceof IASTForStatement) { |
| return ((IASTForStatement) parent).getScope(); |
| } else if (parent instanceof ICPPASTRangeBasedForStatement) { |
| return ((ICPPASTRangeBasedForStatement) parent).getScope(); |
| } else if (parent instanceof IASTCompositeTypeSpecifier) { |
| return ((IASTCompositeTypeSpecifier) parent).getScope(); |
| } else if (parent instanceof ICPPASTNamespaceDefinition) { |
| return ((ICPPASTNamespaceDefinition) parent).getScope(); |
| } else if (parent instanceof ICPPASTSwitchStatement) { |
| return ((ICPPASTSwitchStatement) parent).getScope(); |
| } else if (parent instanceof ICPPASTIfStatement) { |
| return ((ICPPASTIfStatement) parent).getScope(); |
| } else if (parent instanceof ICPPASTWhileStatement) { |
| return ((ICPPASTWhileStatement) parent).getScope(); |
| } else if (parent instanceof ICPPASTTemplateDeclaration) { |
| return ((ICPPASTTemplateDeclaration) parent).getScope(); |
| } else if (parent instanceof ICPPASTCatchHandler) { |
| return ((ICPPASTCatchHandler) parent).getScope(); |
| } |
| } else if (node instanceof IASTStatement) { |
| return getContainingScope((IASTStatement) node); |
| } else if (node instanceof IASTTypeId) { |
| ASTNodeProperty prop = node.getPropertyInParent(); |
| if (prop == ICPPASTTemplateId.TEMPLATE_ID_ARGUMENT || prop == ICPPASTConversionName.TYPE_ID) { |
| node = node.getParent(); // template-id or conversion name |
| while (node instanceof IASTName) { |
| node = node.getParent(); |
| } |
| continue; |
| } else if (prop == ICPPASTFunctionDeclarator.TRAILING_RETURN_TYPE |
| || prop == ICPPASTFunctionDeclarator.EXCEPTION_TYPEID) { |
| IScope result = scopeViaFunctionDtor((ICPPASTFunctionDeclarator) node.getParent()); |
| if (result != null) |
| return result; |
| |
| } |
| } else if (node instanceof IASTParameterDeclaration |
| || node.getPropertyInParent() == ICPPASTFunctionDeclarator.NOEXCEPT_EXPRESSION) { |
| IASTNode parent = node.getParent(); |
| if (parent instanceof ICPPASTFunctionDeclarator) { |
| IScope result = scopeViaFunctionDtor((ICPPASTFunctionDeclarator) parent); |
| if (result != null) |
| return result; |
| } else if (parent instanceof ICPPASTTemplateDeclaration) { |
| return ((ICPPASTTemplateDeclaration) parent).getScope(); |
| } |
| } else if (node instanceof IASTInitializer) { |
| if (node instanceof ICPPASTConstructorChainInitializer) { |
| // The name of the member initializer is resolved in the scope of |
| // the owner of the ctor. |
| ICPPASTConstructorChainInitializer initializer = (ICPPASTConstructorChainInitializer) node; |
| IASTFunctionDefinition fdef = (IASTFunctionDefinition) initializer.getParent(); |
| IBinding binding = fdef.getDeclarator().getName().resolveBinding(); |
| try { |
| return binding.getScope(); |
| } catch (DOMException e) { |
| } |
| } else { |
| IASTNode parent = node.getParent(); |
| if (parent instanceof IASTDeclarator) { |
| IASTDeclarator dtor = (IASTDeclarator) parent; |
| IASTName name = dtor.getName(); |
| if (name instanceof ICPPASTQualifiedName) { |
| return getContainingScope(name.getLastName()); |
| } |
| } else if (parent instanceof ICPPASTConstructorChainInitializer) { |
| // The initializer for the member initializer is resolved in |
| // the body of the ctor. |
| IASTNode temp = getContainingBlockItem(node); |
| if (temp instanceof IASTFunctionDefinition) { |
| IASTCompoundStatement body = (IASTCompoundStatement) ((IASTFunctionDefinition) temp) |
| .getBody(); |
| return body.getScope(); |
| } |
| node = parent; |
| } |
| } |
| } else if (node instanceof IASTExpression) { |
| IASTNode parent = node.getParent(); |
| if (parent instanceof IASTForStatement) { |
| return ((IASTForStatement) parent).getScope(); |
| } else if (parent instanceof ICPPASTRangeBasedForStatement) { |
| return ((ICPPASTRangeBasedForStatement) parent).getScope(); |
| } else if (parent instanceof ICPPASTIfStatement) { |
| return ((ICPPASTIfStatement) parent).getScope(); |
| } else if (parent instanceof ICPPASTSwitchStatement) { |
| return ((ICPPASTSwitchStatement) parent).getScope(); |
| } else if (parent instanceof ICPPASTWhileStatement) { |
| return ((ICPPASTWhileStatement) parent).getScope(); |
| } else if (parent instanceof IASTCompoundStatement) { |
| return ((IASTCompoundStatement) parent).getScope(); |
| } else if (parent instanceof IASTArrayModifier) { |
| IASTNode d = parent.getParent(); |
| while (!(d instanceof IASTDeclarator || d instanceof IASTExpression)) { |
| d = d.getParent(); |
| } |
| if (d instanceof IASTDeclarator) { |
| IASTDeclarator dtor = (IASTDeclarator) d; |
| while (dtor.getNestedDeclarator() != null) |
| dtor = dtor.getNestedDeclarator(); |
| IASTName name = dtor.getName(); |
| if (name instanceof ICPPASTQualifiedName) { |
| return getContainingScope(name.getLastName()); |
| } |
| } |
| } else if (parent instanceof ICPPASTTemplateId |
| && node.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_ID_ARGUMENT) { |
| node = parent; // template-id |
| while (node instanceof IASTName) { |
| node = node.getParent(); |
| } |
| continue; |
| } |
| } else if (node instanceof ICPPASTTemplateParameter) { |
| if (node instanceof ICPPASTTemplatedTypeTemplateParameter && node != inputNode) { |
| return ((ICPPASTTemplatedTypeTemplateParameter) node).asScope(); |
| } |
| IASTNode parent = node.getParent(); |
| if (parent instanceof ICPPASTTemplateDeclaration) { |
| return ((ICPPASTTemplateDeclaration) parent).getScope(); |
| } |
| } else if (node instanceof ICPPASTBaseSpecifier) { |
| ICPPASTCompositeTypeSpecifier compSpec = (ICPPASTCompositeTypeSpecifier) node.getParent(); |
| IASTName n = compSpec.getName().getLastName(); |
| return getContainingScope(n); |
| } else if (node instanceof IASTEnumerator) { |
| node = node.getParent(); |
| if (node instanceof ICPPASTEnumerationSpecifier) { |
| ICPPASTEnumerationSpecifier enumSpec = (ICPPASTEnumerationSpecifier) node; |
| IBinding binding = enumSpec.getName().resolveBinding(); |
| if (binding instanceof ICPPEnumeration) { |
| ICPPEnumeration enumType = (ICPPEnumeration) binding; |
| if (enumType.isScoped()) { |
| return enumType.asScope(); |
| } |
| } |
| } |
| } |
| node = node.getParent(); |
| } |
| return new CPPScope.CPPScopeProblem(inputNode, IProblemBinding.SEMANTIC_BAD_SCOPE, |
| inputNode.getRawSignature().toCharArray()); |
| } |
| |
| private static IScope scopeViaFunctionDtor(ICPPASTFunctionDeclarator dtor) { |
| if (ASTQueries.findTypeRelevantDeclarator(dtor) == dtor) { |
| IASTDeclarator outerDtor = ASTQueries.findOutermostDeclarator(dtor); |
| ASTNodeProperty prop = outerDtor.getPropertyInParent(); |
| if (prop == IASTSimpleDeclaration.DECLARATOR) { |
| return dtor.getFunctionScope(); |
| } |
| if (prop == IASTFunctionDefinition.DECLARATOR) { |
| final IASTCompoundStatement body = (IASTCompoundStatement) ((IASTFunctionDefinition) outerDtor |
| .getParent()).getBody(); |
| if (body != null) |
| return body.getScope(); |
| return dtor.getFunctionScope(); |
| } |
| if (prop == ICPPASTLambdaExpression.DECLARATOR) { |
| final IASTCompoundStatement body = ((ICPPASTLambdaExpression) outerDtor.getParent()).getBody(); |
| if (body != null) |
| return body.getScope(); |
| return dtor.getFunctionScope(); |
| } |
| } |
| return null; |
| } |
| |
| public static IScope getContainingScope(IASTName name) { |
| IScope scope = getContainingScopeOrNull(name); |
| if (scope == null) { |
| return new CPPScope.CPPScopeProblem(name, IProblemBinding.SEMANTIC_BAD_SCOPE); |
| } |
| |
| return scope; |
| } |
| |
| private static IScope getContainingScopeOrNull(IASTName name) { |
| if (name == null) { |
| return null; |
| } |
| IASTNode parent = name.getParent(); |
| try { |
| if (parent instanceof ICPPASTTemplateId) { |
| name = (IASTName) parent; |
| parent = name.getParent(); |
| } |
| |
| if (parent instanceof ICPPASTQualifiedName) { |
| final ICPPASTQualifiedName qname = (ICPPASTQualifiedName) parent; |
| final ICPPASTNameSpecifier[] qualifiers = qname.getQualifier(); |
| int i = 0; |
| for (; i < qualifiers.length; i++) { |
| if (qualifiers[i] == name) |
| break; |
| } |
| final IASTTranslationUnit tu = parent.getTranslationUnit(); |
| if (i == 0) { |
| if (qname.isFullyQualified()) { |
| if (tu == null) |
| return null; |
| return tu.getScope(); |
| } |
| if (qname.getParent() instanceof ICPPASTFieldReference) { |
| name = qname; |
| parent = name.getParent(); |
| } |
| } else { // i > 0 |
| // For template functions we may need to resolve a template parameter |
| // as a parent of an unknown type used as parameter type. |
| IBinding binding = qualifiers[i - 1].resolvePreBinding(); |
| |
| // 7.1.3-7 Unwrap typedefs, delete cv-qualifiers. |
| if (binding instanceof ITypedef) { |
| IType type = getNestedType((ITypedef) binding, TDEF | CVTYPE); |
| if (type instanceof IBinding) { |
| binding = (IBinding) type; |
| } |
| } |
| boolean done = true; |
| IScope scope = null; |
| if (binding instanceof ICPPClassType) { |
| binding = (ICPPClassType) SemanticUtil.mapToAST((ICPPClassType) binding); |
| scope = ((ICPPClassType) binding).getCompositeScope(); |
| } else if (binding instanceof ICPPNamespace) { |
| scope = ((ICPPNamespace) binding).getNamespaceScope(); |
| } else if (binding instanceof ICPPEnumeration) { |
| scope = ((ICPPEnumeration) binding).asScope(); |
| } else if (binding instanceof ICPPUnknownBinding) { |
| scope = ((ICPPUnknownBinding) binding).asScope(); |
| } else if (binding instanceof IProblemBinding) { |
| if (binding instanceof ICPPScope) |
| scope = (IScope) binding; |
| } else { |
| done = false; |
| } |
| if (done) { |
| if (scope == null) { |
| return new CPPScope.CPPScopeProblem(qualifiers[i - 1], IProblemBinding.SEMANTIC_BAD_SCOPE, |
| null); |
| } |
| return scope; |
| } |
| } |
| } |
| |
| if (parent instanceof ICPPASTFieldReference) { |
| final ICPPASTFieldReference fieldReference = (ICPPASTFieldReference) parent; |
| IType type = fieldReference.getFieldOwnerType(); |
| if (type instanceof ICPPParameterPackType) { |
| type = ((ICPPParameterPackType) type).getType(); |
| } |
| type = getUltimateTypeUptoPointers(type); |
| if (type instanceof ICPPClassType) { |
| type = SemanticUtil.mapToAST(type); |
| return ((ICPPClassType) type).getCompositeScope(); |
| } else if (type instanceof ICPPUnknownBinding) { |
| return ((ICPPUnknownBinding) type).asScope(); |
| } else if (type instanceof ICPPUnknownType) { |
| return new CPPUnknownTypeScope(type, null); |
| } else { |
| return new CPPScope.CPPScopeProblem(name, ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION); |
| } |
| } else if (parent instanceof ICPPASTFieldDesignator) { |
| IType type = null; |
| IASTNode node = parent; |
| do { |
| if (node instanceof ICPPASTDeclarator) { |
| type = createType((ICPPASTDeclarator) node); |
| break; |
| } |
| if (node instanceof ICPPASTSimpleTypeConstructorExpression) { |
| type = ((ICPPASTSimpleTypeConstructorExpression) node).getExpressionType(); |
| break; |
| } |
| } while ((node = node.getParent()) != null); |
| |
| if (type != null) { |
| type = getNestedType(type, TDEF | CVTYPE); |
| if (type instanceof ICPPClassType) { |
| type = SemanticUtil.mapToAST(type); |
| return ((ICPPClassType) type).getCompositeScope(); |
| } |
| } |
| return new CPPScope.CPPScopeProblem(name, ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION); |
| } else if (parent instanceof IASTGotoStatement || parent instanceof IASTLabelStatement) { |
| while (!(parent instanceof IASTFunctionDefinition)) { |
| parent = parent.getParent(); |
| } |
| IASTFunctionDefinition fdef = (IASTFunctionDefinition) parent; |
| return ((ICPPASTFunctionDeclarator) fdef.getDeclarator()).getFunctionScope(); |
| } |
| } catch (DOMException e) { |
| IProblemBinding problem = e.getProblem(); |
| if (problem instanceof ICPPScope) |
| return problem; |
| return new CPPScope.CPPScopeProblem(problem.getASTNode(), problem.getID(), problem.getNameCharArray()); |
| } |
| return getContainingScope(parent); |
| } |
| |
| public static IScope getContainingScope(IASTStatement statement) { |
| IASTNode parent = statement.getParent(); |
| IScope scope = null; |
| if (parent instanceof IASTCompoundStatement) { |
| IASTCompoundStatement compound = (IASTCompoundStatement) parent; |
| scope = compound.getScope(); |
| } else if (parent instanceof IASTForStatement) { |
| scope = ((IASTForStatement) parent).getScope(); |
| } else if (parent instanceof ICPPASTRangeBasedForStatement) { |
| scope = ((ICPPASTRangeBasedForStatement) parent).getScope(); |
| } else if (parent instanceof ICPPASTSwitchStatement) { |
| scope = ((ICPPASTSwitchStatement) parent).getScope(); |
| } else if (parent instanceof ICPPASTIfStatement) { |
| scope = ((ICPPASTIfStatement) parent).getScope(); |
| } else if (parent instanceof ICPPASTWhileStatement) { |
| scope = ((ICPPASTWhileStatement) parent).getScope(); |
| } else if (parent instanceof IASTStatement) { |
| scope = getContainingScope((IASTStatement) parent); |
| } else if (parent instanceof IASTFunctionDefinition) { |
| final IASTFunctionDefinition fdef = (IASTFunctionDefinition) parent; |
| if (statement instanceof ICPPASTCatchHandler) |
| return fdef.getScope(); |
| |
| IASTFunctionDeclarator fnDeclarator = fdef.getDeclarator(); |
| IASTName name = findInnermostDeclarator(fnDeclarator).getName().getLastName(); |
| return getContainingScope(name); |
| } |
| |
| if (scope == null) |
| return getContainingScope(parent); |
| return scope; |
| } |
| |
| public static IASTNode getContainingBlockItem(IASTNode node) { |
| if (node == null) |
| return null; |
| if (node.getPropertyInParent() == null) |
| return null; |
| |
| for (IASTNode parent = node.getParent(); parent != null; parent = parent.getParent()) { |
| if (parent instanceof IASTDeclaration) { |
| IASTNode p = parent.getParent(); |
| if (p instanceof IASTDeclarationStatement) |
| return p; |
| return parent; |
| } else if (parent instanceof IASTExpression) { |
| IASTNode p = parent.getParent(); |
| if (p instanceof IASTForStatement) |
| return parent; |
| if (p instanceof ICPPASTRangeBasedForStatement) |
| return parent; |
| if (p instanceof IASTStatement) |
| return p; |
| } else if (parent instanceof IASTStatement || parent instanceof IASTTranslationUnit) { |
| return parent; |
| } else if (parent instanceof IASTFunctionDeclarator |
| && node.getPropertyInParent() == IASTStandardFunctionDeclarator.FUNCTION_PARAMETER) { |
| return node; |
| } else if (parent instanceof IASTEnumerationSpecifier.IASTEnumerator) { |
| return parent; |
| } |
| node = parent; |
| } |
| return null; |
| } |
| |
| static private IBinding resolveBinding(IASTNode node) { |
| IASTName name = null; |
| while (node != null) { |
| if (node instanceof IASTIdExpression) { |
| name = ((IASTIdExpression) node).getName(); |
| if (isLabelReference(node)) { |
| return resolveLabel(name); |
| } |
| break; |
| } else if (node instanceof ICPPASTFieldReference) { |
| name = ((ICPPASTFieldReference) node).getFieldName(); |
| break; |
| } else if (node instanceof ICPPASTFieldDesignator) { |
| name = ((ICPPASTFieldDesignator) node).getName(); |
| break; |
| } else if (node instanceof IASTFunctionCallExpression) { |
| node = ((IASTFunctionCallExpression) node).getFunctionNameExpression(); |
| } else if (node instanceof IASTUnaryExpression) { |
| node = ((IASTUnaryExpression) node).getOperand(); |
| } else if (node instanceof IASTBinaryExpression) { |
| node = ((IASTBinaryExpression) node).getOperand2(); |
| } else { |
| node = null; |
| } |
| } |
| if (name != null) { |
| name = name.getLastName(); |
| IBinding binding = name.getPreBinding(); |
| if (binding == null) { |
| binding = CPPSemantics.resolveBinding(name); |
| name.setBinding(binding); |
| if (name instanceof ICPPASTTemplateId && binding instanceof ICPPSpecialization) { |
| ((ICPPASTTemplateId) name).getTemplateName() |
| .setBinding(((ICPPSpecialization) binding).getSpecializedBinding()); |
| } |
| } |
| return binding; |
| } |
| return null; |
| } |
| |
| private static class CollectProblemsAction extends ASTGenericVisitor { |
| private List<IASTProblem> fProblems = null; |
| |
| CollectProblemsAction() { |
| super(true); |
| } |
| |
| private void addProblem(IASTProblem problem) { |
| if (fProblems == null) { |
| fProblems = new ArrayList<>(); |
| } |
| fProblems.add(problem); |
| } |
| |
| public IASTProblem[] getProblems() { |
| if (fProblems == null) |
| return new IASTProblem[0]; |
| |
| return fProblems.toArray(new IASTProblem[fProblems.size()]); |
| } |
| |
| @Override |
| public int genericVisit(IASTNode node) { |
| if (node instanceof IASTProblemHolder) |
| addProblem(((IASTProblemHolder) node).getProblem()); |
| |
| return PROCESS_CONTINUE; |
| } |
| } |
| |
| public static class CollectDeclarationsAction extends ASTVisitor { |
| private static final int DEFAULT_LIST_SIZE = 8; |
| private IASTName[] decls; |
| private IBinding[] bindings; |
| private int idx = 0; |
| private int kind; |
| private char[] requiredName; |
| private IIndex index; |
| private boolean permissive; |
| |
| private static final int KIND_LABEL = 1; |
| private static final int KIND_OBJ_FN = 2; |
| private static final int KIND_TYPE = 3; |
| private static final int KIND_NAMESPACE = 4; |
| private static final int KIND_COMPOSITE = 5; |
| private static final int KIND_TEMPLATE_PARAMETER = 6; |
| |
| public CollectDeclarationsAction(IBinding binding, boolean permissive) { |
| shouldVisitTranslationUnit = true; |
| shouldVisitNames = true; |
| this.decls = new IASTName[DEFAULT_LIST_SIZE]; |
| this.permissive = permissive; |
| |
| final String bname = binding.getName(); |
| if (bname.length() > 0 && !bname.startsWith("operator")) { //$NON-NLS-1$ |
| requiredName = bname.toCharArray(); |
| } |
| this.bindings = new IBinding[] { binding }; |
| if (binding instanceof ICPPUsingDeclaration) { |
| this.bindings = ((ICPPUsingDeclaration) binding).getDelegates(); |
| kind = KIND_COMPOSITE; |
| } else if (binding instanceof ILabel) { |
| kind = KIND_LABEL; |
| } else if (binding instanceof ICPPTemplateParameter) { |
| kind = KIND_TEMPLATE_PARAMETER; |
| } else if (binding instanceof ICompositeType || binding instanceof ICPPAliasTemplate |
| || binding instanceof ITypedef || binding instanceof IEnumeration) { |
| kind = KIND_TYPE; |
| } else if (binding instanceof ICPPNamespace) { |
| kind = KIND_NAMESPACE; |
| } else if (binding instanceof IParameter) { |
| requiredName = null; |
| kind = KIND_OBJ_FN; |
| } else { |
| kind = KIND_OBJ_FN; |
| } |
| } |
| |
| @Override |
| public int visit(IASTTranslationUnit tu) { |
| index = tu.getIndex(); |
| return PROCESS_CONTINUE; |
| } |
| |
| @Override |
| public int visit(IASTName name) { |
| if (name instanceof ICPPASTQualifiedName) |
| return PROCESS_CONTINUE; |
| if (requiredName != null && !CharArrayUtils.equals(name.getLookupKey(), requiredName)) { |
| return PROCESS_CONTINUE; |
| } |
| |
| ASTNodeProperty prop = name.getPropertyInParent(); |
| if (prop == ICPPASTQualifiedName.SEGMENT_NAME) |
| prop = name.getParent().getPropertyInParent(); |
| |
| switch (kind) { |
| case KIND_TEMPLATE_PARAMETER: |
| if (prop == ICPPASTSimpleTypeTemplateParameter.PARAMETER_NAME |
| || prop == ICPPASTTemplatedTypeTemplateParameter.PARAMETER_NAME) { |
| break; |
| } else if (prop == IASTDeclarator.DECLARATOR_NAME) { |
| IASTNode d = name.getParent(); |
| while (d.getParent() instanceof IASTDeclarator) |
| d = d.getParent(); |
| if (d.getPropertyInParent() == IASTParameterDeclaration.DECLARATOR) { |
| break; |
| } |
| } |
| return PROCESS_CONTINUE; |
| |
| case KIND_LABEL: |
| if (prop == IASTLabelStatement.NAME) |
| break; |
| return PROCESS_CONTINUE; |
| |
| case KIND_TYPE: |
| case KIND_COMPOSITE: |
| if (prop == IASTCompositeTypeSpecifier.TYPE_NAME || prop == ICPPASTAliasDeclaration.ALIAS_NAME |
| || prop == IASTEnumerationSpecifier.ENUMERATION_NAME || prop == ICPPASTUsingDeclaration.NAME) { |
| break; |
| } else if (prop == IASTElaboratedTypeSpecifier.TYPE_NAME) { |
| IASTNode p = name.getParent().getParent(); |
| if (p instanceof IASTParameterDeclaration || (p instanceof IASTSimpleDeclaration |
| && ((IASTSimpleDeclaration) p).getDeclarators().length == 0)) { |
| break; |
| } |
| } else if (prop == IASTDeclarator.DECLARATOR_NAME) { |
| IASTNode p = name.getParent(); |
| while (p instanceof IASTDeclarator) { |
| p = p.getParent(); |
| } |
| if (p instanceof IASTSimpleDeclaration) { |
| IASTDeclSpecifier declSpec = ((IASTSimpleDeclaration) p).getDeclSpecifier(); |
| if (declSpec.getStorageClass() == IASTDeclSpecifier.sc_typedef) |
| break; |
| } |
| } |
| |
| if (kind == KIND_TYPE) |
| return PROCESS_CONTINUE; |
| // $FALL-THROUGH$ |
| |
| case KIND_OBJ_FN: |
| if (prop == IASTDeclarator.DECLARATOR_NAME |
| || prop == IASTEnumerationSpecifier.IASTEnumerator.ENUMERATOR_NAME |
| || prop == ICPPASTUsingDeclaration.NAME |
| || prop == ICPPASTStructuredBindingDeclaration.IDENTIFIER) { |
| break; |
| } |
| return PROCESS_CONTINUE; |
| |
| case KIND_NAMESPACE: |
| if (prop == ICPPASTNamespaceDefinition.NAMESPACE_NAME || prop == ICPPASTNamespaceAlias.ALIAS_NAME) { |
| break; |
| } |
| return PROCESS_CONTINUE; |
| } |
| |
| if (bindings != null) { |
| if (isDeclarationBinding(name.resolveBinding())) { |
| if (decls.length == idx) { |
| decls = Arrays.copyOf(decls, decls.length * 2); |
| } |
| decls[idx++] = name; |
| } |
| } |
| return PROCESS_CONTINUE; |
| } |
| |
| private boolean isDeclarationBinding(IBinding nameBinding) { |
| if (nameBinding != null) { |
| for (IBinding binding : bindings) { |
| if (areEquivalentBindings(nameBinding, binding, index, permissive)) { |
| return true; |
| } |
| // A using declaration is a declaration for the references of its delegates. |
| if (nameBinding instanceof ICPPUsingDeclaration) { |
| if (ArrayUtil.contains(((ICPPUsingDeclaration) nameBinding).getDelegates(), binding)) { |
| return true; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| public IASTName[] getDeclarations() { |
| if (idx < decls.length) { |
| decls = Arrays.copyOf(decls, idx); |
| } |
| return decls; |
| } |
| } |
| |
| private static boolean areEquivalentBindings(IBinding candidate, IBinding target, IIndex index, |
| boolean permissive) { |
| if (permissive && candidate instanceof IProblemBinding && !(target instanceof IProblemBinding)) { |
| IProblemBinding problem = (IProblemBinding) candidate; |
| for (IBinding c : problem.getCandidateBindings()) { |
| if (areEquivalentBindings(c, target, index)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| return areEquivalentBindings(candidate, target, index); |
| } |
| |
| public static boolean areEquivalentBindings(IBinding binding1, IBinding binding2, IIndex index) { |
| if (binding1.equals(binding2)) { |
| return true; |
| } |
| if ((binding1 instanceof IIndexBinding) != (binding2 instanceof IIndexBinding) && index != null) { |
| // Even though we know one of them is an index binding, we need to adapt both because |
| // they might not come from an index with the same number of fragments. So one of them |
| // could be a composite binding and the other one not. |
| binding1 = index.adaptBinding(binding1); |
| binding2 = index.adaptBinding(binding2); |
| |
| if (binding1 == null || binding2 == null) { |
| return false; |
| } |
| if (binding1.equals(binding2)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| protected static IBinding unwindBinding(IBinding binding) { |
| while (true) { |
| if (binding instanceof ICPPSpecialization) { |
| binding = ((ICPPSpecialization) binding).getSpecializedBinding(); |
| } else { |
| break; |
| } |
| } |
| return binding; |
| } |
| |
| public static class CollectReferencesAction extends ASTVisitor { |
| private static final int DEFAULT_LIST_SIZE = 8; |
| private IASTName[] refs; |
| private IBinding[] bindings; |
| private int idx = 0; |
| private int kind; |
| private IIndex index; |
| |
| private static final int KIND_LABEL = 1; |
| private static final int KIND_OBJ_FN = 2; |
| private static final int KIND_TYPE = 3; |
| private static final int KIND_NAMESPACE = 4; |
| private static final int KIND_COMPOSITE = 5; |
| |
| public CollectReferencesAction(IBinding binding) { |
| shouldVisitTranslationUnit = true; |
| shouldVisitNames = true; |
| this.refs = new IASTName[DEFAULT_LIST_SIZE]; |
| |
| binding = unwindBinding(binding); |
| this.bindings = new IBinding[] { binding }; |
| |
| if (binding instanceof ICPPUsingDeclaration) { |
| this.bindings = ((ICPPUsingDeclaration) binding).getDelegates(); |
| kind = KIND_COMPOSITE; |
| } else if (binding instanceof ILabel) { |
| kind = KIND_LABEL; |
| } else if (binding instanceof ICompositeType || binding instanceof ITypedef |
| || binding instanceof IEnumeration) { |
| kind = KIND_TYPE; |
| } else if (binding instanceof ICPPNamespace) { |
| kind = KIND_NAMESPACE; |
| } else if (binding instanceof ICPPTemplateParameter) { |
| kind = KIND_COMPOSITE; |
| } else { |
| kind = KIND_OBJ_FN; |
| } |
| } |
| |
| @Override |
| public int visit(IASTTranslationUnit tu) { |
| index = tu.getIndex(); |
| return PROCESS_CONTINUE; |
| } |
| |
| @Override |
| public int visit(IASTName name) { |
| if (name instanceof ICPPASTQualifiedName || name instanceof ICPPASTTemplateId) |
| return PROCESS_CONTINUE; |
| |
| ASTNodeProperty prop = name.getPropertyInParent(); |
| ASTNodeProperty p2 = null; |
| if (prop == ICPPASTQualifiedName.SEGMENT_NAME) { |
| p2 = prop; |
| prop = name.getParent().getPropertyInParent(); |
| } |
| |
| switch (kind) { |
| case KIND_LABEL: |
| if (prop == IASTGotoStatement.NAME || prop == IASTIdExpression.ID_NAME) |
| break; |
| return PROCESS_CONTINUE; |
| |
| case KIND_TYPE: |
| case KIND_COMPOSITE: |
| if (prop == IASTNamedTypeSpecifier.NAME || prop == ICPPASTPointerToMember.NAME |
| || prop == ICPPASTUsingDeclaration.NAME |
| || prop == ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier.NAME_SPECIFIER |
| || prop == ICPPASTTemplateId.TEMPLATE_NAME || p2 == ICPPASTQualifiedName.SEGMENT_NAME) { |
| break; |
| } else if (prop == IASTElaboratedTypeSpecifier.TYPE_NAME) { |
| IASTNode p = name.getParent().getParent(); |
| if (!(p instanceof IASTSimpleDeclaration) |
| || ((IASTSimpleDeclaration) p).getDeclarators().length > 0) { |
| break; |
| } |
| } |
| if (kind == KIND_TYPE) |
| return PROCESS_CONTINUE; |
| //$FALL-THROUGH$ |
| case KIND_OBJ_FN: |
| if (prop == IASTIdExpression.ID_NAME || prop == IASTFieldReference.FIELD_NAME |
| || prop == ICPPASTUsingDirective.QUALIFIED_NAME || prop == ICPPASTUsingDeclaration.NAME |
| || prop == IASTFunctionCallExpression.FUNCTION_NAME || prop == ICPPASTUsingDeclaration.NAME |
| || prop == IASTNamedTypeSpecifier.NAME || prop == ICPPASTConstructorChainInitializer.MEMBER_ID |
| || prop == ICPPASTTemplateId.TEMPLATE_ID_ARGUMENT || prop == ICPPASTCapture.IDENTIFIER |
| || prop == IASTImplicitNameOwner.IMPLICIT_NAME) { |
| break; |
| } |
| return PROCESS_CONTINUE; |
| |
| case KIND_NAMESPACE: |
| if (prop == ICPPASTUsingDirective.QUALIFIED_NAME || prop == ICPPASTNamespaceAlias.MAPPING_NAME |
| || prop == ICPPASTUsingDeclaration.NAME || p2 == ICPPASTQualifiedName.SEGMENT_NAME) { |
| break; |
| } |
| return PROCESS_CONTINUE; |
| } |
| |
| if (bindings != null) { |
| if (isReferenceBinding(name.resolveBinding())) { |
| if (refs.length == idx) { |
| refs = Arrays.copyOf(refs, refs.length * 2); |
| } |
| refs[idx++] = name; |
| } |
| } |
| return PROCESS_CONTINUE; |
| } |
| |
| private boolean isReferenceBinding(IBinding nameBinding) { |
| nameBinding = unwindBinding(nameBinding); |
| if (nameBinding != null) { |
| for (IBinding binding : bindings) { |
| if (areEquivalentBindings(nameBinding, binding, index)) { |
| return true; |
| } |
| } |
| if (nameBinding instanceof ICPPUsingDeclaration) { |
| IBinding[] delegates = ((ICPPUsingDeclaration) nameBinding).getDelegates(); |
| for (IBinding delegate : delegates) { |
| if (isReferenceBinding(delegate)) { |
| return true; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| public IASTName[] getReferences() { |
| if (idx < refs.length) { |
| refs = Arrays.copyOf(refs, idx); |
| } |
| return refs; |
| } |
| } |
| |
| /** |
| * Generate a function type for an implicit function. |
| * NOTE: This does not correctly handle parameters with typedef types. |
| */ |
| public static ICPPFunctionType createImplicitFunctionType(IType returnType, IParameter[] parameters, |
| boolean isConst, boolean isVolatile) { |
| IType[] pTypes = new IType[parameters.length]; |
| IType pt = null; |
| |
| for (int i = 0; i < parameters.length; i++) { |
| pt = parameters[i].getType(); |
| |
| // remove qualifiers |
| if (pt instanceof IQualifierType) { |
| pt = ((IQualifierType) pt).getType(); |
| } |
| |
| if (pt instanceof IArrayType) { |
| pt = new CPPPointerType(((IArrayType) pt).getType()); |
| } else if (pt instanceof IFunctionType) { |
| pt = new CPPPointerType(pt); |
| } |
| |
| pTypes[i] = pt; |
| } |
| |
| return new CPPFunctionType(returnType, pTypes, |
| null /* TODO(havogt) [except.spec] p.14 (c++11) noexcept for implicitly declared special member functions not implemented */, |
| isConst, isVolatile, false, false, false); |
| } |
| |
| /** |
| * Creates the type for the given type id. |
| */ |
| public static IType createType(IASTTypeId typeid) { |
| return createType(typeid.getAbstractDeclarator()); |
| } |
| |
| /** |
| * Creates the type for a parameter declaration. |
| */ |
| public static IType createType(final ICPPASTParameterDeclaration pdecl, boolean forFuncType) { |
| IASTDeclSpecifier pDeclSpec = pdecl.getDeclSpecifier(); |
| ICPPASTDeclarator pDtor = pdecl.getDeclarator(); |
| IType pt; |
| PlaceholderKind placeholder = usesAuto(pDeclSpec); |
| if (placeholder != null) { |
| pt = createAutoType(pDeclSpec, pDtor, 0, placeholder); |
| } else { |
| pt = createType(pDeclSpec); |
| if (pDtor != null) { |
| pt = createType(pt, pDtor); |
| } |
| } |
| |
| pt = adjustParameterType(pt, forFuncType); |
| |
| if (pDtor != null && findInnermostDeclarator(pDtor).declaresParameterPack()) { |
| pt = new CPPParameterPackType(pt); |
| } |
| return pt; |
| } |
| |
| private static boolean hasFieldNamedValue(ICPPClassSpecialization instance) { |
| return Arrays.stream(instance.getFields()).anyMatch(field -> field.getName().equals(VALUE_STR)); |
| } |
| |
| public static Optional<ICPPClassSpecialization> findTupleSizeWithValueMember(IType type, IScope scope, |
| IASTNode beforeNode) { |
| ICPPTemplateArgument[] templateArguments = new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) }; |
| return findClassTemplateInstance(scope, STD_TUPLE_SIZE_STR, templateArguments, beforeNode) |
| .filter(CPPVisitor::hasFieldNamedValue); |
| } |
| |
| private static Optional<ICPPClassSpecialization> findClassTemplateInstance(IScope scope, String templateName, |
| ICPPTemplateArgument[] templateArguments, IASTNode point) { |
| IBinding[] tupleSizeBindings = CPPSemantics.findBindingsForQualifiedName(scope, templateName, point); |
| return Arrays.stream(tupleSizeBindings).filter(ICPPClassTemplate.class::isInstance) |
| .map(ICPPClassTemplate.class::cast) |
| .map(template -> CPPTemplates.instantiate(template, templateArguments)) |
| .filter(ICPPClassSpecialization.class::isInstance).map(ICPPClassSpecialization.class::cast) |
| .filter(Objects::nonNull).findFirst(); |
| } |
| |
| private static IType determineTupleElementType(IType type, IScope scope, IASTName name, int index) { |
| ICPPTemplateArgument indexArgument = new CPPTemplateNonTypeArgument(IntegralValue.create(index), |
| CPPVisitor.get_SIZE_T()); |
| ICPPTemplateArgument[] templateArguments = new ICPPTemplateArgument[] { indexArgument, |
| new CPPTemplateTypeArgument(type) }; |
| return toStream(findClassTemplateInstance(scope, STD_TUPLE_ELEMENT_STR, templateArguments, name)) |
| .map(ICPPClassSpecialization::getCompositeScope) |
| // Look for "type" in class scope with CPPSemantics.findBindings to also consider base classes |
| .map(instanceScope -> CPPSemantics.findBindings(instanceScope, TYPE_STR.toCharArray(), false, name)) |
| .flatMap(Arrays::stream).filter(IType.class::isInstance).map(IType.class::cast) |
| .map(SemanticUtil::getSimplifiedType).findFirst() |
| .orElse(ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE); |
| } |
| |
| private static ICPPASTInitializerClause getInitializerClause(ICPPASTStructuredBindingDeclaration declaration) { |
| IASTInitializer initializer = declaration.getInitializer(); |
| ICPPASTInitializerClause initClause = null; |
| if (initializer != null) { |
| initClause = getInitClauseForInitializer(initializer); |
| } else { |
| IASTNode declarationParent = declaration.getParent(); |
| if (declarationParent instanceof ICPPASTRangeBasedForStatement) { |
| ICPPASTRangeBasedForStatement rangeBasedForParent = (ICPPASTRangeBasedForStatement) declarationParent; |
| initClause = getAutoInitClauseForRangeBasedFor(rangeBasedForParent); |
| } |
| } |
| return initClause; |
| } |
| |
| public static IType createType(ICPPASTStructuredBindingDeclaration declaration, IASTName name) { |
| ICPPASTInitializerClause initClause = getInitializerClause(declaration); |
| |
| if (initClause == null) { |
| return ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE; |
| } |
| |
| ICPPEvaluation evaluation = initClause.getEvaluation(); |
| IType eType = evaluation.getType(); |
| IType unwrappedType = SemanticUtil.getNestedType(eType, TDEF | ALLCVQ); |
| IType initializerType = deduceInitializerType(declaration, name, unwrappedType); |
| if (initializerType == ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE) { |
| return initializerType; |
| } |
| IASTDeclSpecifier declSpec = declaration.getDeclSpecifier(); |
| IType qualifiedType = SemanticUtil.addQualifiers(initializerType, |
| declSpec.isConst() || SemanticUtil.isConst(eType), |
| declSpec.isVolatile() || SemanticUtil.isVolatile(eType), declSpec.isRestrict()); |
| RefQualifier refQualifier = declaration.getRefQualifier(); |
| if (refQualifier == null) { |
| return qualifiedType; |
| } |
| return new CPPReferenceType(qualifiedType, shallBecomeRvalueReference(evaluation, refQualifier, declSpec)); |
| } |
| |
| public static boolean hasConstexprStaticIntegralValueField(ICPPClassType type, long expectedValue) { |
| return Arrays.stream(ClassTypeHelper.getFields(type)).filter(IS_STATIC_VARIABLE).filter(IS_NAMED_VALUE) |
| .filter(HAS_INTEGRAL_TYPE).filter(HAS_CONST_TYPE).filter(field -> { |
| return variableHasInitialNumberValue(field, expectedValue); |
| }).findFirst().isPresent(); |
| } |
| |
| private static boolean variableHasInitialNumberValue(IVariable variable, long expectedValue) { |
| IValue initialValue = variable.getInitialValue(); |
| if (initialValue == null) { |
| return false; |
| } |
| Number numberValue = initialValue.numberValue(); |
| if (numberValue == null) { |
| return false; |
| } |
| return numberValue.longValue() == expectedValue; |
| } |
| |
| private static IType deduceInitializerType(ICPPASTStructuredBindingDeclaration declaration, IASTName name, |
| IType unwrappedType) { |
| if (unwrappedType instanceof IArrayType) { |
| IArrayType arrayType = (IArrayType) unwrappedType; |
| return arrayType.getType(); |
| } else if (unwrappedType instanceof ICPPClassType) { |
| int index = Arrays.asList(declaration.getNames()).indexOf(name); |
| IScope scope = CPPSemantics.getLookupScope(name); |
| Optional<ICPPClassSpecialization> tupleSizeInstance = findTupleSizeWithValueMember(unwrappedType, scope, |
| name); |
| if (tupleSizeInstance.isPresent()) { |
| int numberOfNames = declaration.getNames().length; |
| if (hasConstexprStaticIntegralValueField(tupleSizeInstance.get(), numberOfNames)) { |
| return determineTupleElementType(unwrappedType, scope, name, index); |
| } |
| } else { |
| ICPPClassType classType = (ICPPClassType) unwrappedType; |
| return Arrays.stream(ClassTypeHelper.getFields(classType)).filter(IS_STATIC_VARIABLE.negate()) |
| .skip(index).findFirst().map(IField::getType) |
| .orElse(ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE); |
| } |
| } |
| return ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE; |
| } |
| |
| /** |
| * |
| * Determines the reference type of a name in a structured binding based on its {@code evaluation}, the {@code refQualifier} and the {@code declSpecifier}. |
| * It performs perfect forwarding in case of a forwarding reference, i.e. if the declaration specifier is exactly "auto &&", |
| * Otherwise it is always an rvalue reference if the declaration specifier contains && |
| * |
| * Example: |
| * auto && [element] = get(); // element is an rvalue if get() is an rvalue, otherwise an lvalue |
| * auto const && [element] = get(); //element is always an rvalue, get() needs to be an rvalue too |
| * |
| */ |
| private static boolean shallBecomeRvalueReference(ICPPEvaluation evaluation, RefQualifier refQualifier, |
| IASTDeclSpecifier declSpecifier) { |
| |
| if (refQualifier == RefQualifier.RVALUE) { |
| return evaluation.getValueCategory() != ValueCategory.LVALUE || declSpecifier.isConst() |
| || declSpecifier.isVolatile(); |
| } |
| return false; |
| } |
| |
| private static IType createFunctionType(IType returnType, ICPPASTFunctionDeclarator fnDtor) { |
| IType[] pTypes = createParameterTypes(fnDtor); |
| |
| IASTName name = fnDtor.getName().getLastName(); |
| if (name instanceof ICPPASTConversionName) { |
| returnType = createType(((ICPPASTConversionName) name).getTypeId()); |
| } else { |
| returnType = applyAttributes(returnType, fnDtor); |
| returnType = getPointerTypes(returnType, fnDtor); |
| } |
| |
| RefQualifier refQualifier = fnDtor.getRefQualifier(); |
| CPPFunctionType type = new CPPFunctionType(returnType, pTypes, fnDtor.getNoexceptEvaluation(), fnDtor.isConst(), |
| fnDtor.isVolatile(), refQualifier != null, refQualifier == RefQualifier.RVALUE, fnDtor.takesVarArgs()); |
| final IASTDeclarator nested = fnDtor.getNestedDeclarator(); |
| if (nested != null) { |
| return createType(type, nested); |
| } |
| return type; |
| } |
| |
| /** |
| * Creates an array of types for the parameters of the given function declarator. |
| */ |
| public static IType[] createParameterTypes(ICPPASTFunctionDeclarator fnDtor) { |
| ICPPASTParameterDeclaration[] params = fnDtor.getParameters(); |
| IType[] pTypes = new IType[params.length]; |
| for (int i = 0; i < params.length; i++) { |
| pTypes[i] = createType(params[i], true); |
| } |
| |
| if (pTypes.length == 1 && SemanticUtil.isVoidType(pTypes[0])) { |
| return IType.EMPTY_TYPE_ARRAY; // f(void) is the same as f(). |
| } |
| return pTypes; |
| } |
| |
| /** |
| * Adjusts the parameter type according to 8.3.5-3: |
| * cv-qualifiers are deleted, arrays and function types are converted to pointers. |
| */ |
| static IType adjustParameterType(final IType pt, boolean forFunctionType) { |
| // Bug 239975 |
| IType t = SemanticUtil.getNestedType(pt, TDEF); |
| if (t instanceof IArrayType) { |
| IArrayType at = (IArrayType) t; |
| return new CPPPointerType(at.getType()); |
| } |
| if (t instanceof IFunctionType) { |
| return new CPPPointerType(pt); |
| } |
| |
| // 8.3.5-3 |
| // Any cv-qualifier modifying a parameter type is deleted. The parameter type remains |
| // to be qualified. |
| if (forFunctionType && SemanticUtil.getCVQualifier(t) != CVQualifier.NONE) { |
| return SemanticUtil.getNestedType(t, TDEF | ALLCVQ); |
| } |
| return pt; |
| } |
| |
| private static IType getPointerTypes(IType type, IASTDeclarator declarator) { |
| IASTPointerOperator[] ptrOps = declarator.getPointerOperators(); |
| for (IASTPointerOperator ptrOp : ptrOps) { |
| if (ptrOp instanceof ICPPASTPointerToMember) { |
| type = new CPPPointerToMemberType(type, (ICPPASTPointerToMember) ptrOp); |
| } else if (ptrOp instanceof IASTPointer) { |
| type = new CPPPointerType(type, (IASTPointer) ptrOp); |
| } else if (ptrOp instanceof ICPPASTReferenceOperator) { |
| final ICPPASTReferenceOperator refOp = (ICPPASTReferenceOperator) ptrOp; |
| type = new CPPReferenceType(type, refOp.isRValueReference()); |
| } |
| } |
| return type; |
| } |
| |
| private static IType applyAttributes(IType type, IASTDeclarator declarator) { |
| if (type instanceof IBasicType) { |
| IBasicType basicType = (IBasicType) type; |
| if (basicType.getKind() == IBasicType.Kind.eInt) { |
| IASTAttribute[] attributes = declarator.getAttributes(); |
| for (IASTAttribute attribute : attributes) { |
| char[] name = attribute.getName(); |
| if (CharArrayUtils.equals(name, "__mode__") || CharArrayUtils.equals(name, "mode")) { //$NON-NLS-1$ //$NON-NLS-2$ |
| char[] mode = AttributeUtil.getSimpleArgument(attribute); |
| if (CharArrayUtils.equals(mode, "__QI__") || CharArrayUtils.equals(mode, "QI")) { //$NON-NLS-1$ //$NON-NLS-2$ |
| type = new CPPBasicType(IBasicType.Kind.eChar, |
| basicType.isUnsigned() ? IBasicType.IS_UNSIGNED : IBasicType.IS_SIGNED); |
| } else if (CharArrayUtils.equals(mode, "__HI__") || CharArrayUtils.equals(mode, "HI")) { //$NON-NLS-1$ //$NON-NLS-2$ |
| type = new CPPBasicType(IBasicType.Kind.eInt, |
| IBasicType.IS_SHORT | getSignModifiers(basicType)); |
| } else if (CharArrayUtils.equals(mode, "__SI__") || CharArrayUtils.equals(mode, "SI")) { //$NON-NLS-1$ //$NON-NLS-2$ |
| type = new CPPBasicType(IBasicType.Kind.eInt, getSignModifiers(basicType)); |
| } else if (CharArrayUtils.equals(mode, "__DI__") || CharArrayUtils.equals(mode, "DI")) { //$NON-NLS-1$ //$NON-NLS-2$ |
| SizeofCalculator sizeofs = new SizeofCalculator(declarator.getTranslationUnit()); |
| int modifier; |
| if (sizeofs.sizeof_long != null && sizeofs.sizeof_int != null |
| && sizeofs.sizeof_long.size == 2 * sizeofs.sizeof_int.size) { |
| modifier = IBasicType.IS_LONG; |
| } else { |
| modifier = IBasicType.IS_LONG_LONG; |
| } |
| type = new CPPBasicType(IBasicType.Kind.eInt, modifier | getSignModifiers(basicType)); |
| } else if (CharArrayUtils.equals(mode, "__word__") || CharArrayUtils.equals(mode, "word")) { //$NON-NLS-1$ //$NON-NLS-2$ |
| type = new CPPBasicType(IBasicType.Kind.eInt, |
| IBasicType.IS_LONG | getSignModifiers(basicType)); |
| } |
| } |
| } |
| } |
| } |
| return type; |
| } |
| |
| private static int getSignModifiers(IBasicType type) { |
| return type.getModifiers() & (IBasicType.IS_SIGNED | IBasicType.IS_UNSIGNED); |
| } |
| |
| private static IType getArrayType(IType type, IASTArrayDeclarator declarator) { |
| IASTArrayModifier[] mods = declarator.getArrayModifiers(); |
| for (int i = mods.length; --i >= 0;) { |
| IASTArrayModifier mod = mods[i]; |
| IASTExpression sizeExpression = mod.getConstantExpression(); |
| if (sizeExpression != null) { |
| type = new CPPArrayType(type, sizeExpression); |
| } else { |
| IValue sizeValue = null; |
| IASTInitializer initializer = declarator.getInitializer(); |
| if (initializer instanceof IASTEqualsInitializer) { |
| IASTInitializerClause clause = ((IASTEqualsInitializer) initializer).getInitializerClause(); |
| if (clause instanceof IASTInitializerList) { |
| IASTInitializerClause[] clauses = ((IASTInitializerList) clause).getClauses(); |
| sizeValue = IntegralValue.create(clauses.length); |
| } else if (clause instanceof ICPPASTLiteralExpression) { |
| ICPPEvaluation value = ((ICPPASTExpression) clause).getEvaluation(); |
| IType valueType = value.getType(); |
| if (valueType instanceof IArrayType) { |
| sizeValue = ((IArrayType) valueType).getSize(); |
| } |
| } |
| } |
| type = new CPPArrayType(type, sizeValue); |
| } |
| } |
| return type; |
| } |
| |
| public static PlaceholderKind usesAuto(IASTDeclSpecifier declSpec) { |
| if (declSpec instanceof ICPPASTSimpleDeclSpecifier) { |
| int declSpecType = ((ICPPASTSimpleDeclSpecifier) declSpec).getType(); |
| if (declSpecType == IASTSimpleDeclSpecifier.t_auto) { |
| return PlaceholderKind.Auto; |
| } else if (declSpecType == IASTSimpleDeclSpecifier.t_decltype_auto) { |
| return PlaceholderKind.DecltypeAuto; |
| } |
| } |
| return null; |
| } |
| |
| public static IType createType(ICPPASTInitCapture capture) { |
| IASTDeclarator declarator = capture.getDeclarator(); |
| ICPPASTInitializerClause initClause = getAutoInitClauseForDeclarator(declarator); |
| if (initClause == null) { |
| return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; |
| } |
| return createAutoType(initClause.getEvaluation(), null, declarator); |
| } |
| |
| public static IType createType(IASTDeclarator declarator) { |
| // Resolve placeholders by default. |
| return createType(declarator, RESOLVE_PLACEHOLDERS); |
| } |
| |
| public static IType createType(IASTDeclarator declarator, int flags) { |
| if (declarator == null) |
| return ProblemType.NO_NAME; |
| |
| CPPSemantics.pushLookupPoint(declarator); |
| try { |
| declarator = findOutermostDeclarator(declarator); |
| IASTNode parent = declarator.getParent(); |
| |
| IASTDeclSpecifier declSpec = null; |
| boolean isPackExpansion = false; |
| if (parent instanceof IASTSimpleDeclaration) { |
| declSpec = ((IASTSimpleDeclaration) parent).getDeclSpecifier(); |
| } else if (parent instanceof IASTParameterDeclaration) { |
| declSpec = ((IASTParameterDeclaration) parent).getDeclSpecifier(); |
| } else if (parent instanceof IASTFunctionDefinition) { |
| declSpec = ((IASTFunctionDefinition) parent).getDeclSpecifier(); |
| } else if (parent instanceof ICPPASTTypeId) { |
| final ICPPASTTypeId typeId = (ICPPASTTypeId) parent; |
| declSpec = typeId.getDeclSpecifier(); |
| isPackExpansion = typeId.isPackExpansion(); |
| } else if (parent instanceof ICPPASTInitCapture) { |
| return createType((ICPPASTInitCapture) parent); |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| |
| PlaceholderKind placeholder = usesAuto(declSpec); |
| if (placeholder != null) { |
| return createAutoType(declSpec, declarator, flags, placeholder); |
| } |
| |
| IType type = createType(declSpec); |
| type = createType(type, declarator, flags); |
| |
| // constexpr implies toplevel-const |
| type = makeConstIfConstexpr(type, declSpec, declarator); |
| |
| // C++ specification 8.3.4.3 and 8.5.1.4 |
| IASTNode initClause = declarator.getInitializer(); |
| if (initClause instanceof IASTEqualsInitializer) { |
| initClause = ((IASTEqualsInitializer) initClause).getInitializerClause(); |
| if (initClause instanceof IASTLiteralExpression && SemanticUtil.isConst(type)) { |
| // The check here avoids performing the computation in getValueOfInitialize() |
| // in cases where we wouldn't use it anyways because we don't have a CPPBasicType. |
| if (SemanticUtil.getNestedType(type, TDEF | ALLCVQ) instanceof CPPBasicType) { |
| type = associateTypeWithValue(type, |
| SemanticUtil.getValueOfInitializer(declarator.getInitializer(), type)); |
| } |
| } |
| } |
| if (initClause instanceof IASTInitializerList) { |
| IType t = SemanticUtil.getNestedType(type, TDEF); |
| if (t instanceof IArrayType) { |
| IArrayType at = (IArrayType) t; |
| if (at.getSize() == null) { |
| type = new CPPArrayType(at.getType(), |
| IntegralValue.create(((IASTInitializerList) initClause).getSize())); |
| } |
| } |
| } |
| |
| if (isPackExpansion) { |
| type = new CPPParameterPackType(type); |
| } |
| return type; |
| } finally { |
| CPPSemantics.popLookupPoint(); |
| } |
| } |
| |
| /** |
| * Returns an IType representing the same type as the argument, but |
| * which also knows its value. |
| * |
| * This only has an effect for built-in types (modulo cv-qualification |
| * and typedefs), and in cases where the a concrete numerical value |
| * is known. |
| * |
| * The returned IType object may be different from the argument. |
| */ |
| public static IType associateTypeWithValue(IType type, IValue value) { |
| Number numberValue = value.numberValue(); |
| if (numberValue != null) { |
| return associateTypeWithValue(type, numberValue.longValue()); |
| } |
| return type; |
| } |
| |
| private static IType associateTypeWithValue(IType type, long value) { |
| if (type instanceof ITypeContainer) { |
| ITypeContainer typeContainer = (ITypeContainer) type; |
| IType oldInner = typeContainer.getType(); |
| IType newInner = associateTypeWithValue(oldInner, value); |
| if (oldInner != newInner) { |
| ITypeContainer clone = (ITypeContainer) typeContainer.clone(); |
| clone.setType(newInner); |
| return clone; |
| } |
| } else if (type instanceof CPPBasicType) { |
| CPPBasicType clone = ((CPPBasicType) type).clone(); |
| clone.setAssociatedNumericalValue(value); |
| return clone; |
| } |
| return type; |
| } |
| |
| private static IType createAutoParameterType(IASTDeclSpecifier declSpec, IASTDeclarator declarator, |
| ICPPASTParameterDeclaration declaration, PlaceholderKind placeholder) { |
| // decltype(auto) is not allowed in parameters. |
| if (placeholder == PlaceholderKind.DecltypeAuto) { |
| return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE; |
| } |
| |
| // In C++14, auto is only allowed in lambda parameters. |
| // In the Concepts TS (not implemented yet), this restriction is removed. |
| ICPPASTFunctionDeclarator functionDeclarator = (ICPPASTFunctionDeclarator) declaration.getParent(); |
| if (functionDeclarator.getParent() instanceof ICPPASTLambdaExpression) { |
| ICPPASTLambdaExpression lambda = (ICPPASTLambdaExpression) functionDeclarator.getParent(); |
| CPPClosureType closure = (CPPClosureType) lambda.getExpressionType(); |
| ICPPTemplateParameter[] templateParameters = closure.getInventedTemplateParameterList(); |
| |
| // Find the invented template parameter corresponding to this 'auto'. |
| int templateParameterIndex = -1; |
| for (ICPPASTParameterDeclaration parameter : functionDeclarator.getParameters()) { |
| if (usesAuto(parameter.getDeclSpecifier()) != null) { |
| ++templateParameterIndex; |
| } |
| if (parameter == declaration) |
| break; |
| } |
| if (templateParameterIndex >= 0 && templateParameterIndex < templateParameters.length) { |
| ICPPTemplateParameter templateParameter = templateParameters[templateParameterIndex]; |
| if (templateParameter instanceof ICPPTemplateTypeParameter) { |
| return createType((ICPPTemplateTypeParameter) templateParameter, declarator); |
| } |
| } |
| } |
| return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; |
| } |
| |
| private static ICPPASTInitializerClause getInitClauseForInitializer(IASTInitializer initClause) { |
| if (initClause instanceof IASTEqualsInitializer) { |
| return (ICPPASTInitializerClause) ((IASTEqualsInitializer) initClause).getInitializerClause(); |
| } else if (initClause instanceof ICPPASTConstructorInitializer) { |
| IASTInitializerClause[] arguments = ((ICPPASTConstructorInitializer) initClause).getArguments(); |
| if (arguments.length == 1) { |
| return (ICPPASTInitializerClause) arguments[0]; |
| } |
| } else if (initClause instanceof ICPPASTInitializerClause) { |
| if (initClause instanceof ICPPASTInitializerList) { |
| IASTInitializerClause[] clauses = ((ICPPASTInitializerList) initClause).getClauses(); |
| if (clauses.length == 1) { |
| return (ICPPASTInitializerClause) clauses[0]; |
| } |
| } |
| return (ICPPASTInitializerClause) initClause; |
| } |
| return null; |
| } |
| |
| private static ICPPASTInitializerClause getAutoInitClauseForRangeBasedFor(ICPPASTRangeBasedForStatement forStmt) { |
| // See 6.5.4 The range-based for statement [stmt.ranged] |
| IASTInitializerClause forInit = forStmt.getInitializerClause(); |
| IASTExpression beginExpr = null; |
| if (forInit instanceof IASTExpression) { |
| final IASTExpression expr = (IASTExpression) forInit; |
| IType type = SemanticUtil.getNestedType(expr.getExpressionType(), TDEF | CVTYPE); |
| if (type instanceof IArrayType) { |
| beginExpr = expr.copy(); |
| } |
| } |
| if (beginExpr == null) { |
| IASTImplicitName[] implicits = forStmt.getImplicitNames(); |
| if (implicits.length > 0) { |
| IBinding b = implicits[0].getBinding(); |
| CPPASTName name = new CPPASTName(); |
| name.setBinding(b); |
| IASTInitializerClause[] beginCallArguments = new IASTInitializerClause[] { forInit.copy() }; |
| if (b instanceof ICPPMethod && forInit instanceof IASTExpression) { |
| beginExpr = new CPPASTFunctionCallExpression( |
| new CPPASTFieldReference(name, (IASTExpression) forInit.copy()), beginCallArguments); |
| } else { |
| beginExpr = new CPPASTFunctionCallExpression(new CPPASTIdExpression(name), beginCallArguments); |
| } |
| } else { |
| return null; |
| } |
| } |
| ICPPASTInitializerClause autoInitClause = new CPPASTUnaryExpression(IASTUnaryExpression.op_star, beginExpr); |
| autoInitClause.setParent(forStmt); |
| autoInitClause.setPropertyInParent(ICPPASTRangeBasedForStatement.INITIALIZER); |
| return autoInitClause; |
| } |
| |
| private static ICPPASTInitializerClause getAutoInitClauseForDeclarator(IASTDeclarator declarator) { |
| IASTInitializer initClause = declarator.getInitializer(); |
| return getInitClauseForInitializer(initClause); |
| } |
| |
| private static IType createAutoType(final IASTDeclSpecifier declSpec, IASTDeclarator declarator, int flags, |
| PlaceholderKind placeholderKind) { |
| IType cannotDeduce = placeholderKind == PlaceholderKind.Auto ? ProblemType.CANNOT_DEDUCE_AUTO_TYPE |
| : ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE; |
| Set<IASTDeclarator> recursionProtectionSet = autoTypeDeclarators.get(); |
| if (!recursionProtectionSet.add(declarator)) { |
| // Detected a self referring auto type, e.g.: auto x = x; |
| return cannotDeduce; |
| } |
| |
| try { |
| if (declarator instanceof ICPPASTFunctionDeclarator) { |
| return createAutoFunctionType(declSpec, (ICPPASTFunctionDeclarator) declarator, flags, placeholderKind); |
| } |
| if (declarator.getParent() instanceof ICPPASTParameterDeclaration) { |
| if (declarator.getParent().getParent() instanceof ICPPASTFunctionDeclarator) { |
| // 'auto' used as the type of a function parameter. |
| return createAutoParameterType(declSpec, declarator, |
| (ICPPASTParameterDeclaration) declarator.getParent(), placeholderKind); |
| } else { |
| if (placeholderKind == PlaceholderKind.Auto) { |
| // 'auto' used as the type of a template parameter. |
| // This is a partially supported C++17 feature. |
| return new CPPPlaceholderType(placeholderKind); |
| } else { |
| return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE; |
| } |
| } |
| } |
| ICPPASTInitializerClause autoInitClause = null; |
| IASTNode parent = declarator.getParent().getParent(); |
| if (parent instanceof ICPPASTNewExpression) { |
| IASTInitializer initializer = ((ICPPASTNewExpression) parent).getInitializer(); |
| if (initializer != null) { |
| IASTInitializerClause[] arguments = ((ICPPASTConstructorInitializer) initializer).getArguments(); |
| if (arguments.length == 1) { |
| autoInitClause = (ICPPASTInitializerClause) arguments[0]; |
| } |
| } |
| } else if (parent instanceof ICPPASTRangeBasedForStatement) { |
| autoInitClause = getAutoInitClauseForRangeBasedFor((ICPPASTRangeBasedForStatement) parent); |
| if (autoInitClause == null) { |
| return cannotDeduce; |
| } |
| } else if (parent instanceof IASTCompositeTypeSpecifier |
| && declSpec.getStorageClass() != IASTDeclSpecifier.sc_static) { |
| // Non-static auto-typed class members are not allowed. |
| return ProblemType.AUTO_FOR_NON_STATIC_FIELD; |
| } else { |
| autoInitClause = getAutoInitClauseForDeclarator(declarator); |
| } |
| if (autoInitClause == null) { |
| return cannotDeduce; |
| } |
| if (placeholderKind == PlaceholderKind.Auto) { |
| return createAutoType(autoInitClause.getEvaluation(), declSpec, declarator); |
| } else /* decltype(auto) */ { |
| if (declarator.getPointerOperators().length > 0) { |
| // 'decltype(auto)' cannot be combined with * or & the way 'auto' can. |
| return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE; |
| } |
| if (declSpec.isConst() || declSpec.isVolatile()) { |
| // 'decltype(auto)' cannot be combined with any type specifiers. [dcl.type.auto.deduct] |
| return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE; |
| } |
| if (autoInitClause instanceof IASTExpression) { |
| return getDeclType((IASTExpression) autoInitClause); |
| } else { |
| return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE; |
| } |
| } |
| } finally { |
| recursionProtectionSet.remove(declarator); |
| } |
| } |
| |
| private static IType createAutoType(final ICPPEvaluation evaluation, IASTDeclSpecifier declSpec, |
| IASTDeclarator declarator) { |
| // C++0x: 7.1.6.4 |
| IType type = AutoTypeResolver.AUTO_TYPE; |
| IType initType = null; |
| ValueCategory valueCat = null; |
| initType = evaluation.getType(); |
| valueCat = evaluation.getValueCategory(); |
| if (initType == null || initType instanceof ISemanticProblem) { |
| return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; |
| } |
| ICPPClassTemplate initializer_list_template = null; |
| if (evaluation instanceof EvalInitList) { |
| initializer_list_template = get_initializer_list(); |
| if (initializer_list_template == null) { |
| return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; |
| } |
| type = (IType) CPPTemplates.instantiate(initializer_list_template, |
| new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) }); |
| if (type instanceof IProblemBinding) { |
| return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; |
| } |
| } |
| if (declSpec != null && declarator != null) { |
| type = decorateType(type, declSpec, declarator); |
| } |
| ICPPFunctionTemplate template = new AutoTypeResolver(type); |
| CPPTemplateParameterMap paramMap = new CPPTemplateParameterMap(1); |
| TemplateArgumentDeduction.deduceFromFunctionArgs(template, Collections.singletonList(initType), |
| Collections.singletonList(valueCat), paramMap); |
| ICPPTemplateArgument argument = paramMap.getArgument(0, 0); |
| if (argument == null) { |
| return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; |
| } |
| type = argument.getTypeValue(); |
| if (type instanceof TypeOfDependentExpression) { |
| // After binding to 'auto', a dependent type no longer acts like 'decltype(expr)'. |
| // For example, after instantiation it's no longer wrapped into a reference type |
| // if it's an lvalue the way 'decltype(expr)' usually is. |
| ((TypeOfDependentExpression) type).setIsForDecltype(false); |
| } |
| IType t = SemanticUtil.substituteTypedef(type, initType); |
| if (t != null) |
| type = t; |
| if (evaluation instanceof EvalInitList) { |
| type = (IType) CPPTemplates.instantiate(initializer_list_template, |
| new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) }); |
| } |
| if (declSpec != null && declarator != null) { |
| type = decorateType(type, declSpec, declarator); |
| } |
| return type; |
| } |
| |
| private static class ReturnTypeDeducer extends ReturnStatementVisitor { |
| private static final ICPPEvaluation voidEval = new EvalFixed(CPPSemantics.VOID_TYPE, ValueCategory.PRVALUE, |
| IntegralValue.UNKNOWN); |
| |
| private ICPPEvaluation[] fReturnEvals = ICPPEvaluation.EMPTY_ARRAY; |
| private boolean fEncounteredReturnStatement = false; |
| |
| protected ReturnTypeDeducer(IASTFunctionDefinition func) { |
| super(func); |
| } |
| |
| @Override |
| protected void onReturnStatement(IASTReturnStatement stmt) { |
| fEncounteredReturnStatement = true; |
| IASTInitializerClause returnExpression = stmt.getReturnArgument(); |
| ICPPEvaluation returnEval; |
| if (returnExpression == null) { |
| returnEval = voidEval; |
| } else { |
| returnEval = ((ICPPASTInitializerClause) returnExpression).getEvaluation(); |
| } |
| IType returnType = returnEval.getType(); |
| if (returnType instanceof ISemanticProblem) { |
| // If a function makes a recursive call in some of its return statements, |
| // the type those return expressions will be a problem type. We ignore |
| // these, because we can still successfully deduce from another return |
| // statement that is not recursive. |
| // If all return statements are recursive, fReturnEvals will remain empty |
| // and deduceReturnType() will error out as desired. |
| return; |
| } |
| |
| fReturnEvals = ArrayUtil.append(fReturnEvals, returnEval); |
| } |
| |
| public ICPPEvaluation[] getReturnEvaluations() { |
| if (fReturnEvals.length == 0 && !fEncounteredReturnStatement) { |
| fReturnEvals = ArrayUtil.append(fReturnEvals, voidEval); |
| } |
| return ArrayUtil.trim(fReturnEvals); |
| } |
| } |
| |
| private static IType deduceTypeFromReturnEvaluation(ICPPEvaluation returnEval, IASTDeclSpecifier autoDeclSpec, |
| IASTDeclarator autoDeclarator, PlaceholderKind placeholder) { |
| // [dcl.type.auto.deduct] p3: |
| // If the deduction is for a return statement and the initializer is a |
| // braced-init-list, the proram is ill-formed. |
| if (returnEval instanceof EvalInitList) { |
| return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; |
| } |
| |
| if (placeholder == PlaceholderKind.DecltypeAuto) { |
| if (autoDeclarator != null && autoDeclarator.getPointerOperators().length > 0) { |
| // 'decltype(auto)' cannot be combined with * or & the way 'auto' can. |
| return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE; |
| } |
| if (autoDeclSpec.isConst() || autoDeclSpec.isVolatile()) { |
| // 'decltype(auto)' cannot be combined with any type specifiers. [dcl.type.auto.deduct] |
| return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE; |
| } |
| return CPPSemantics.getDeclTypeForEvaluation(returnEval); |
| } else /* auto */ { |
| return createAutoType(returnEval, autoDeclSpec, autoDeclarator); |
| } |
| } |
| |
| public static IType deduceReturnType(IASTStatement functionBody, IASTDeclSpecifier autoDeclSpec, |
| IASTDeclarator autoDeclarator, PlaceholderKind placeholder) { |
| ICPPEvaluation[] returnEvals = ICPPEvaluation.EMPTY_ARRAY; |
| if (functionBody != null) { |
| ReturnTypeDeducer deducer = new ReturnTypeDeducer(null); |
| functionBody.accept(deducer); |
| returnEvals = deducer.getReturnEvaluations(); |
| } |
| if (returnEvals.length == 0) { |
| return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; |
| } |
| |
| // [dcl.spec.auto] p7: |
| // If a function with a declared return type that contains a placeholder type has multiple |
| // return statements, the return type is deduced for each such return statement. |
| // If the type deduced is not the same in each deduction, the program is ill-formed. |
| IType returnType = deduceTypeFromReturnEvaluation(returnEvals[0], autoDeclSpec, autoDeclarator, placeholder); |
| for (int i = 1; i < returnEvals.length; ++i) { |
| IType otherType = deduceTypeFromReturnEvaluation(returnEvals[i], autoDeclSpec, autoDeclarator, placeholder); |
| if (!returnType.isSameType(otherType)) { |
| return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; |
| } |
| } |
| return returnType; |
| } |
| |
| /** |
| * C++0x: [8.3.5-2] |
| */ |
| private static IType createAutoFunctionType(IASTDeclSpecifier declSpec, ICPPASTFunctionDeclarator declarator, |
| int flags, PlaceholderKind placeholder) { |
| IType returnType = null; |
| IASTDeclSpecifier declSpecForDeduction = null; |
| IASTDeclarator declaratorForDeduction = null; |
| IASTTypeId trailingReturnType = declarator.getTrailingReturnType(); |
| if (trailingReturnType == null) { |
| // No trailing return type. |
| if ((flags & RESOLVE_PLACEHOLDERS) != 0) { |
| declSpecForDeduction = declSpec; |
| declaratorForDeduction = declarator; |
| } else { |
| returnType = new CPPPlaceholderType(PlaceholderKind.Auto); |
| } |
| } else { |
| IASTDeclSpecifier trailingDeclSpec = trailingReturnType.getDeclSpecifier(); |
| IASTDeclarator trailingDeclarator = trailingReturnType.getAbstractDeclarator(); |
| PlaceholderKind trailingPlaceholder = usesAuto(trailingDeclSpec); |
| if (trailingPlaceholder != null && !(trailingDeclarator instanceof IASTFunctionDeclarator)) { |
| // Trailing return type uses 'auto', other than to introduce |
| // another trailing return type for a function type, so we'll |
| // need to look at the function body and deduce the return type. |
| declSpecForDeduction = trailingDeclSpec; |
| declaratorForDeduction = trailingDeclarator; |
| placeholder = trailingPlaceholder; |
| } else { |
| // Trailing return type specifies the type. |
| returnType = createType(trailingDeclarator); |
| returnType = qualifyType(returnType, declSpec); |
| } |
| } |
| |
| if (returnType == null) { |
| // Try to deduce return type from return statement. |
| |
| // [dcl.spec.auto] p12: |
| // A function declared with a return type that uses a placeholder type |
| // shall not be virtual. |
| if (((ICPPASTDeclSpecifier) declSpec).isVirtual()) |
| return ProblemType.AUTO_FOR_VIRTUAL_METHOD; |
| |
| ICPPASTFunctionDefinition definition = CPPFunction.getFunctionDefinition(declarator); |
| if (definition != null) { |
| returnType = deduceReturnType(definition.getBody(), declSpecForDeduction, declaratorForDeduction, |
| placeholder); |
| } |
| } |
| |
| if (returnType != null) { |
| if ((flags & ONLY_RETURN_TYPE) != 0) { |
| return returnType; |
| } |
| |
| // Do not use createFunctionType() because that would decorate the return type |
| // with pointer operators from e.g. an 'auto &', but we have already done that |
| // above. |
| IType[] pTypes = createParameterTypes(declarator); |
| RefQualifier refQualifier = declarator.getRefQualifier(); |
| IType result = new CPPFunctionType(returnType, pTypes, declarator.getNoexceptEvaluation(), |
| declarator.isConst(), declarator.isVolatile(), refQualifier != null, |
| refQualifier == RefQualifier.RVALUE, declarator.takesVarArgs()); |
| final IASTDeclarator nested = declarator.getNestedDeclarator(); |
| if (nested != null) { |
| result = createType(result, nested); |
| } |
| return result; |
| } |
| return ProblemType.NO_NAME; |
| |
| } |
| |
| public static IType createType(IASTDeclSpecifier declSpec) { |
| IType type = getBaseType(declSpec); |
| return qualifyType(type, declSpec); |
| } |
| |
| private static IType getBaseType(IASTDeclSpecifier declSpec) { |
| IASTName name; |
| if (declSpec instanceof ICPPASTCompositeTypeSpecifier) { |
| name = ((ICPPASTCompositeTypeSpecifier) declSpec).getName(); |
| } else if (declSpec instanceof ICPPASTNamedTypeSpecifier) { |
| name = ((ICPPASTNamedTypeSpecifier) declSpec).getName(); |
| } else if (declSpec instanceof ICPPASTElaboratedTypeSpecifier) { |
| name = ((ICPPASTElaboratedTypeSpecifier) declSpec).getName(); |
| } else if (declSpec instanceof IASTEnumerationSpecifier) { |
| name = ((IASTEnumerationSpecifier) declSpec).getName(); |
| } else if (declSpec instanceof ICPPASTTypeTransformationSpecifier) { |
| ICPPASTTypeTransformationSpecifier spec = (ICPPASTTypeTransformationSpecifier) declSpec; |
| return new CPPUnaryTypeTransformation(spec.getOperator(), createType(spec.getOperand())); |
| } else if (declSpec instanceof ICPPASTSimpleDeclSpecifier) { |
| ICPPASTSimpleDeclSpecifier spec = (ICPPASTSimpleDeclSpecifier) declSpec; |
| // Check for decltype(expr) |
| IType type = getDeclType(spec); |
| if (type != null) |
| return type; |
| return new CPPBasicType(spec); |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| if (name == null) |
| return ProblemType.NO_NAME; |
| |
| IBinding binding = name.resolvePreBinding(); |
| if (!(binding instanceof IProblemBinding)) { |
| if (binding instanceof ICPPConstructor) |
| return ((ICPPConstructor) binding).getClassOwner(); |
| |
| if (binding instanceof IType) |
| return (IType) binding; |
| } |
| return ProblemType.UNRESOLVED_NAME; |
| } |
| |
| // Helper function for createAutoType(). |
| private static IType decorateType(IType type, IASTDeclSpecifier declSpec, IASTDeclarator declarator) { |
| type = qualifyType(type, declSpec); |
| type = makeConstIfConstexpr(type, declSpec, declarator); |
| // Ignore function declarator because we already handled that in createAutoFunctionType(). |
| return createType(type, declarator, ONLY_RETURN_TYPE); |
| } |
| |
| private static IType makeConstIfConstexpr(IType type, IASTDeclSpecifier declSpec, IASTDeclarator declarator) { |
| // [dcl.constexpr] p9: constexpr on a variable makes it const |
| if (!(declarator instanceof IASTFunctionDeclarator)) { |
| if (declSpec instanceof ICPPASTDeclSpecifier) { |
| if (((ICPPASTDeclSpecifier) declSpec).isConstexpr()) { |
| return SemanticUtil.constQualify(type); |
| } |
| } |
| } |
| return type; |
| } |
| |
| private static IType qualifyType(IType type, IASTDeclSpecifier declSpec) { |
| return SemanticUtil.addQualifiers(type, declSpec.isConst(), declSpec.isVolatile(), declSpec.isRestrict()); |
| } |
| |
| private static IType createType(IType baseType, IASTDeclarator declarator) { |
| return createType(baseType, declarator, 0); |
| } |
| |
| private static IType createType(IType baseType, IASTDeclarator declarator, int flags) { |
| if (((flags & ONLY_RETURN_TYPE) == 0) && declarator instanceof ICPPASTFunctionDeclarator) |
| return createFunctionType(baseType, (ICPPASTFunctionDeclarator) declarator); |
| |
| IType type = baseType; |
| type = applyAttributes(type, declarator); |
| type = getPointerTypes(type, declarator); |
| if (declarator instanceof IASTArrayDeclarator) |
| type = getArrayType(type, (IASTArrayDeclarator) declarator); |
| |
| IASTDeclarator nested = declarator.getNestedDeclarator(); |
| if (nested != null) { |
| return createType(type, nested); |
| } |
| return type; |
| } |
| |
| /** |
| * Computes the type for decltype(expr) or typeof(expr). |
| */ |
| private static IType getDeclType(ICPPASTSimpleDeclSpecifier spec) { |
| IASTExpression expr = spec.getDeclTypeExpression(); |
| if (expr == null) { |
| return null; |
| } |
| int specifierType = spec.getType(); |
| if (specifierType == IASTSimpleDeclSpecifier.t_decltype) { |
| return getDeclType(expr); |
| } |
| return expr.getExpressionType(); |
| } |
| |
| /** |
| * Computes the type for an expression in decltype(expr) context. |
| */ |
| private static IType getDeclType(IASTExpression expr) { |
| IASTName namedEntity = null; |
| if (expr instanceof IASTIdExpression) { |
| namedEntity = ((IASTIdExpression) expr).getName(); |
| } else if (expr instanceof IASTFieldReference) { |
| namedEntity = ((IASTFieldReference) expr).getFieldName(); |
| } |
| if (namedEntity != null) { |
| IBinding b = namedEntity.resolvePreBinding(); |
| if (b instanceof IType) { |
| return (IType) b; |
| } |
| if (b instanceof IVariable) { |
| return ((IVariable) b).getType(); |
| } |
| if (b instanceof IFunction) { |
| return ((IFunction) b).getType(); |
| } |
| } |
| IType type = expr.getExpressionType(); |
| switch (expr.getValueCategory()) { |
| case XVALUE: |
| type = new CPPReferenceType(type, true); |
| break; |
| case LVALUE: |
| type = new CPPReferenceType(type, false); |
| break; |
| case PRVALUE: |
| break; |
| } |
| return type; |
| } |
| |
| public static IType getImpliedObjectType(IScope scope) { |
| try { |
| IASTNode node = null; |
| while (scope != null) { |
| if (scope instanceof ICPPBlockScope || scope instanceof ICPPFunctionScope) { |
| node = ASTInternal.getPhysicalNodeOfScope(scope); |
| if (node instanceof IASTFunctionDeclarator) |
| break; |
| if (node.getParent() instanceof IASTFunctionDefinition) |
| break; |
| } else if (scope instanceof ICPPClassScope) { |
| // Reached a class scope without a function scope in between. |
| // Might be in the default member initializer on a field. |
| IType type = ((ICPPClassScope) scope).getClassType(); |
| if (type instanceof ICPPClassTemplate) { |
| type = (ICPPClassType) ((ICPPClassTemplate) type).asDeferredInstance(); |
| } |
| return type; |
| } |
| scope = scope.getParent(); |
| } |
| if (node != null) { |
| if (node.getParent() instanceof IASTFunctionDefinition) { |
| IASTFunctionDefinition def = (IASTFunctionDefinition) node.getParent(); |
| node = def.getDeclarator(); |
| } |
| if (node instanceof IASTFunctionDeclarator) { |
| ICPPASTFunctionDeclarator dtor = (ICPPASTFunctionDeclarator) node; |
| IASTName funcName = findInnermostDeclarator(dtor).getName().getLastName(); |
| IScope s = getContainingScope(funcName); |
| while (s instanceof ICPPTemplateScope) { |
| s = s.getParent(); |
| } |
| if (s instanceof ICPPClassScope) { |
| ICPPClassScope cScope = (ICPPClassScope) s; |
| IType type = cScope.getClassType(); |
| if (type instanceof ICPPClassTemplate) { |
| type = (ICPPClassType) ((ICPPClassTemplate) type).asDeferredInstance(); |
| } |
| return SemanticUtil.addQualifiers(type, dtor.isConst(), dtor.isVolatile(), false); |
| } |
| } |
| } |
| } catch (DOMException e) { |
| return e.getProblem(); |
| } |
| return null; |
| } |
| |
| public static IType getPointerDiffType() { |
| IType t = getStdType(PTRDIFF_T); |
| return t != null ? t : CPPBasicType.LONG; |
| } |
| |
| private static IType getStdType(char[] name) { |
| IASTNode node = CPPSemantics.getCurrentLookupPoint(); |
| if (node == null) |
| return null; |
| ASTTranslationUnit ast = (ASTTranslationUnit) node.getTranslationUnit(); |
| IBinding[] std = ast.getScope().find(STD, ast); |
| for (IBinding binding : std) { |
| if (binding instanceof ICPPNamespace) { |
| final ICPPNamespaceScope scope = ((ICPPNamespace) binding).getNamespaceScope(); |
| IBinding[] bs = CPPSemantics.findBindings(scope, name, false, node); |
| if (bs.length > 0) { |
| for (IBinding b : bs) { |
| if (b instanceof IType && CPPSemantics.declaredBefore(b, node, false)) { |
| return (IType) b; |
| } |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| public static IType get_type_info() { |
| IType t = getStdType(TYPE_INFO); |
| return t != null ? t : CPPBasicType.INT; |
| } |
| |
| public static IType get_SIZE_T() { |
| IType t = getStdType(SIZE_T); |
| return t != null ? t : CPPBasicType.UNSIGNED_LONG; |
| } |
| |
| public static ICPPClassTemplate get_initializer_list() { |
| IType t = getStdType(INITIALIZER_LIST); |
| if (t instanceof ICPPClassTemplate) |
| return (ICPPClassTemplate) t; |
| return null; |
| } |
| |
| public static IASTProblem[] getProblems(IASTTranslationUnit tu) { |
| CollectProblemsAction action = new CollectProblemsAction(); |
| tu.accept(action); |
| return action.getProblems(); |
| } |
| |
| public static IASTName[] getReferences(IASTTranslationUnit tu, IBinding binding) { |
| CollectReferencesAction action = new CollectReferencesAction(binding); |
| tu.accept(action); |
| return action.getReferences(); |
| } |
| |
| public static IASTName[] getImplicitReferences(IASTTranslationUnit tu, IBinding binding) { |
| CollectReferencesAction action = new CollectReferencesAction(binding) { |
| { |
| shouldVisitNames = false; |
| shouldVisitImplicitNames = true; |
| shouldVisitImplicitNameAlternates = true; |
| } |
| }; |
| tu.accept(action); |
| return action.getReferences(); |
| } |
| |
| public static IASTName[] getDeclarations(IASTTranslationUnit tu, IBinding binding) { |
| return getDeclarations(tu, binding, false); |
| } |
| |
| public static IASTName[] getDeclarations(IASTTranslationUnit tu, IBinding binding, boolean permissive) { |
| CollectDeclarationsAction action = new CollectDeclarationsAction(binding, permissive); |
| tu.accept(action); |
| |
| IASTName[] found = action.getDeclarations(); |
| if (found.length == 0 && binding instanceof ICPPSpecialization && binding instanceof ICPPInternalBinding) { |
| IASTNode node = ((ICPPInternalBinding) binding).getDefinition(); |
| if (node == null) { |
| IASTNode[] nds = ((ICPPInternalBinding) binding).getDeclarations(); |
| if (nds != null && nds.length > 0) |
| node = nds[0]; |
| } |
| if (node != null) { |
| IASTName name = null; |
| if (node instanceof IASTDeclarator) { |
| name = ((IASTDeclarator) node).getName(); |
| } else if (node instanceof IASTName) { |
| name = (IASTName) node; |
| } |
| if (name != null) |
| found = new IASTName[] { name }; |
| } |
| } |
| |
| return found; |
| } |
| |
| public static String[] getQualifiedName(IBinding binding) { |
| String[] ns = null; |
| for (IBinding owner = binding.getOwner(); owner != null; owner = owner.getOwner()) { |
| if (owner instanceof ICPPEnumeration && !((ICPPEnumeration) owner).isScoped()) { |
| continue; |
| } |
| String name = owner.getName(); |
| if (name == null) |
| break; |
| if (owner instanceof ICPPFunction) |
| break; |
| if (owner instanceof ICPPNamespace && name.length() == 0) { |
| continue; |
| } |
| |
| ns = ArrayUtil.append(String.class, ns, name); |
| } |
| ns = ArrayUtil.trim(String.class, ns); |
| String[] result = new String[ns.length + 1]; |
| for (int i = ns.length; --i >= 0;) { |
| result[ns.length - i - 1] = ns[i]; |
| } |
| result[ns.length] = binding.getName(); |
| return result; |
| } |
| |
| public static char[][] getQualifiedNameCharArray(IBinding binding) { |
| char[][] ns = EMPTY_CHAR_ARRAY_ARRAY; |
| ns = ArrayUtil.append(ns, binding.getNameCharArray()); |
| for (IBinding owner = binding.getOwner(); owner != null; owner = owner.getOwner()) { |
| char[] name = owner.getNameCharArray(); |
| if (name == null) |
| break; |
| if (owner instanceof ICPPFunction) |
| break; |
| if (owner instanceof ICPPNamespace && name.length == 0) |
| continue; |
| |
| ns = ArrayUtil.append(ns, name); |
| } |
| ns = ArrayUtil.trim(ns); |
| ArrayUtil.reverse(ns); |
| return ns; |
| } |
| |
| public static boolean isExternC(IASTNode node) { |
| while (node != null) { |
| node = node.getParent(); |
| if (node instanceof ICPPASTLinkageSpecification) { |
| if ("\"C\"".equals(((ICPPASTLinkageSpecification) node).getLiteral())) { //$NON-NLS-1$ |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| public static boolean isExternC(IASTNode definition, IASTNode[] declarations) { |
| if (isExternC(definition)) |
| return true; |
| |
| if (declarations != null) { |
| for (IASTNode element : declarations) { |
| if (isExternC(element)) |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Searches for the function or class enclosing the given node. May return <code>null</code>. |
| */ |
| public static IBinding findEnclosingFunctionOrClass(IASTNode node) { |
| IASTName name = null; |
| for (; node != null; node = node.getParent()) { |
| if (node instanceof IASTFunctionDefinition) { |
| IASTDeclarator dtor = findInnermostDeclarator(((IASTFunctionDefinition) node).getDeclarator()); |
| if (dtor != null) { |
| name = dtor.getName(); |
| } |
| break; |
| } |
| if (node instanceof IASTCompositeTypeSpecifier) { |
| name = ((IASTCompositeTypeSpecifier) node).getName(); |
| break; |
| } |
| } |
| if (name == null) |
| return null; |
| |
| return name.resolveBinding(); |
| } |
| |
| public static IBinding findNameOwner(IASTName name, boolean allowFunction) { |
| IASTNode node = name.getLastName(); |
| while (node instanceof IASTName) { |
| if (node instanceof ICPPASTQualifiedName) { |
| ICPPASTNameSpecifier[] segments = ((ICPPASTQualifiedName) node).getAllSegments(); |
| int i = segments.length; |
| while (--i >= 0) { |
| if (segments[i] == name) { |
| break; |
| } |
| } |
| if (--i < 0) |
| break; |
| IBinding binding = segments[i].resolveBinding(); |
| if (binding instanceof IIndexBinding && binding instanceof ICPPClassType) { |
| binding = (ICPPClassType) SemanticUtil.mapToAST((ICPPClassType) binding); |
| } |
| return bindingToOwner(binding); |
| } |
| name = (IASTName) node; |
| node = node.getParent(); |
| } |
| return findDeclarationOwner(node, allowFunction); |
| } |
| |
| private static IBinding bindingToOwner(IBinding b) { |
| if (b instanceof ITypedef) { |
| IType t = SemanticUtil.getNestedType((IType) b, TDEF); |
| if (t instanceof IBinding) |
| return (IBinding) t; |
| |
| return b; |
| } |
| while (b instanceof ICPPNamespaceAlias) { |
| b = ((ICPPNamespaceAlias) b).getBinding(); |
| } |
| return b; |
| } |
| |
| /** |
| * Searches for the first class, namespace, or function, if <code>allowFunction</code> |
| * is <code>true</code>, enclosing the declaration the provided node belongs to and returns |
| * the binding for it. Returns <code>null</code>, if the declaration is not enclosed by any |
| * of the above constructs. |
| */ |
| public static IBinding findDeclarationOwner(IASTNode node, boolean allowFunction) { |
| IASTName name = findDeclarationOwnerDefinition(node, allowFunction); |
| if (name == null) |
| return null; |
| |
| return name.resolveBinding(); |
| } |
| |
| public static IASTName findDeclarationOwnerDefinition(IASTNode node, boolean allowFunction) { |
| // Search for declaration |
| boolean isNonSimpleElabDecl = false; |
| while (!(node instanceof IASTDeclaration) && !(node instanceof ICPPASTLambdaExpression)) { |
| if (node == null) |
| return null; |
| if (node instanceof IASTElaboratedTypeSpecifier) { |
| isNonSimpleElabDecl = true; |
| final IASTNode parent = node.getParent(); |
| if (parent instanceof IASTSimpleDeclaration) { |
| final IASTSimpleDeclaration decl = (IASTSimpleDeclaration) parent; |
| if (decl.getDeclarators().length == 0) { |
| isNonSimpleElabDecl = false; |
| } |
| } |
| } else if (node instanceof IASTEnumerator) { |
| break; |
| } |
| node = node.getParent(); |
| } |
| |
| boolean isFriend = isFriendDeclaration(node); |
| |
| // Search for enclosing binding. |
| for (node = node.getParent(); node != null; node = node.getParent()) { |
| if (node instanceof IASTFunctionDefinition) { |
| if (allowFunction) { |
| IASTDeclarator dtor = findInnermostDeclarator(((IASTFunctionDefinition) node).getDeclarator()); |
| if (dtor != null) { |
| return dtor.getName(); |
| } |
| } |
| return null; |
| } |
| if (node instanceof IASTCompositeTypeSpecifier) { |
| if (isFriend || isNonSimpleElabDecl) |
| continue; |
| return ((IASTCompositeTypeSpecifier) node).getName(); |
| } |
| if (node instanceof ICPPASTNamespaceDefinition) { |
| return ((ICPPASTNamespaceDefinition) node).getName(); |
| } |
| if (node instanceof ICPPASTEnumerationSpecifier) { |
| return ((ICPPASTEnumerationSpecifier) node).getName(); |
| } |
| if (node instanceof ICPPASTLambdaExpression) { |
| return ((ICPPASTLambdaExpression) node).getClosureTypeName(); |
| } |
| } |
| return null; |
| } |
| |
| public static boolean doesNotSpecifyType(IASTDeclSpecifier declspec) { |
| if (declspec instanceof ICPPASTSimpleDeclSpecifier) { |
| ICPPASTSimpleDeclSpecifier ds = (ICPPASTSimpleDeclSpecifier) declspec; |
| if (ds.getType() == IASTSimpleDeclSpecifier.t_unspecified) { |
| if (ds.isShort() || ds.isLong() || ds.isLongLong() || ds.isSigned() || ds.isUnsigned()) |
| return false; |
| |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public static ICPPASTDeclarator findInnermostDeclarator(ICPPASTDeclarator dtor) { |
| return (ICPPASTDeclarator) ASTQueries.findInnermostDeclarator(dtor); |
| } |
| |
| /** |
| * Traverses a chain of nested homogeneous left-to-right-associative binary expressions and |
| * returns a list of their operands in left-to-right order. For example, for the expression |
| * a + b * c + d, it will return a list containing expressions: a, b * c, and d. |
| * |
| * @param binaryExpression the top-level binary expression |
| * @return a list of expression operands from left to right |
| */ |
| public static IASTExpression[] getOperandsOfMultiExpression(IASTBinaryExpression binaryExpression) { |
| int operator = binaryExpression.getOperator(); |
| IASTExpression[] operands = new IASTExpression[2]; |
| IASTExpression node; |
| int len = 0; |
| do { |
| operands = ArrayUtil.appendAt(operands, len++, binaryExpression.getOperand2()); |
| node = binaryExpression.getOperand1(); |
| if (!(node instanceof IASTBinaryExpression)) { |
| break; |
| } |
| binaryExpression = (IASTBinaryExpression) node; |
| } while (binaryExpression.getOperator() == operator); |
| operands = ArrayUtil.appendAt(operands, len++, node); |
| operands = ArrayUtil.trim(operands, len); |
| ArrayUtil.reverse(operands); |
| return operands; |
| } |
| |
| /** |
| * Determines whether the given {@code namespace} definition denotes |
| * an anonymous namespace. |
| * @param namespace |
| * @return {@code true} if the {@code namespace} is anonymous, false otherwise |
| */ |
| public static boolean isAnonymousNamespace(ICPPASTNamespaceDefinition namespace) { |
| IASTName name = namespace.getName(); |
| return name == null || name.toString().isEmpty(); |
| } |
| } |