blob: 37f1353c852368ab4dfae97f8bf2a7647235d9b5 [file] [log] [blame]
/*******************************************************************************
* 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);
}
private 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();
}
}