Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 9dd1c4b31a08d644532678f9738974aeab9391f7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*******************************************************************************
 * Copyright (c) 2012, 2015 Nathan Ridge.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Nathan Ridge - initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.core.dom.ast.cpp;

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 java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPInheritance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPInheritance.FinalOverriderMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;

/**
 * This class exposes semantic queries about C++ code to clients such
 * as code analysis.
 *
 * @since 5.5
 */
public class SemanticQueries {

	public static boolean isCopyOrMoveConstructor(ICPPConstructor constructor) {
		return isCopyOrMoveConstructor(constructor, CopyOrMoveConstructorKind.COPY_OR_MOVE);
	}

	public static boolean isMoveConstructor(ICPPConstructor constructor) {
		return isCopyOrMoveConstructor(constructor, CopyOrMoveConstructorKind.MOVE);
	}

	public static boolean isCopyConstructor(ICPPConstructor constructor) {
		return isCopyOrMoveConstructor(constructor, CopyOrMoveConstructorKind.COPY);
	}

	private enum CopyOrMoveConstructorKind { COPY, MOVE, COPY_OR_MOVE }

	private static boolean isCopyOrMoveConstructor(ICPPConstructor constructor, CopyOrMoveConstructorKind kind) {
		// 12.8/2-3 [class.copy]:
		// "A non-template constructor for class X is a copy [move] constructor
		//  if its first parameter is of type X&[&], const X&[&], volatile X&[&]
		//  or const volatile X&[&], and either there are no other parametrs or
		//  else all other parametrs have default arguments."
		if (constructor instanceof ICPPFunctionTemplate)
			return false;
		if (!isCallableWithNumberOfArguments(constructor, 1))
			return false;
		IType firstArgumentType = constructor.getType().getParameterTypes()[0];
		firstArgumentType = SemanticUtil.getNestedType(firstArgumentType, TDEF);
		if (!(firstArgumentType instanceof ICPPReferenceType))
			return false;
		ICPPReferenceType firstArgReferenceType = (ICPPReferenceType) firstArgumentType;
		boolean isRvalue = firstArgReferenceType.isRValueReference();
		if (isRvalue && kind == CopyOrMoveConstructorKind.COPY)
			return false;
		if (!isRvalue && kind == CopyOrMoveConstructorKind.MOVE)
			return false;
		firstArgumentType = firstArgReferenceType.getType();
		firstArgumentType = SemanticUtil.getNestedType(firstArgumentType, CVTYPE);
		ICPPClassType classType = constructor.getClassOwner();
		if (classType instanceof ICPPClassTemplate)
			classType = CPPTemplates.createDeferredInstance((ICPPClassTemplate) classType);
		return firstArgumentType.isSameType(classType);
	}

	private static boolean isCallableWithNumberOfArguments(ICPPFunction function, int numArguments) {
		return function.getParameters().length >= numArguments
			&& function.getRequiredArgumentCount() <= numArguments;
	}

	/**
	 * Returns all pure virtual methods of a class. Inherited pure virtual methods
	 * that have not been implemented are also returned.
	 *
	 * NOTE: The method produces complete results for template instantiations but
	 * doesn't take into account base classes and methods dependent on unspecified
	 * template parameters.
	 *
	 * @param classType
	 *            the class whose pure virtual methods should be returned
	 * @return an array containing all pure virtual methods of the class
	 * @since 6.4
	 */
	public static ICPPMethod[] getPureVirtualMethods(ICPPClassType classType) {
		FinalOverriderMap finalOverriderMap = CPPInheritance.getFinalOverriderMap(classType);
		List<ICPPMethod> pureVirtualMethods = new ArrayList<>();
		for (ICPPMethod method : finalOverriderMap.getMap().keySet()) {
			if (method.isPureVirtual()) {
				Map<Integer, List<ICPPMethod>> finalOverriders = finalOverriderMap.getMap().get(method);
				for (Integer subobjectNumber : finalOverriders.keySet()) {
					List<ICPPMethod> overridersForSubobject = finalOverriders.get(subobjectNumber);
					if (overridersForSubobject.size() == 1 && overridersForSubobject.get(0) == method) {
						pureVirtualMethods.add(method);
					}
				}
			}
		}
		return pureVirtualMethods.toArray(new ICPPMethod[pureVirtualMethods.size()]);
	}
	
	/**
	 * @deprecated Use {@link SemanticQueries}{@link #getPureVirtualMethods(ICPPClassType)} instead.
	 * @since 5.6
	 */
	@Deprecated
	public static ICPPMethod[] getPureVirtualMethods(ICPPClassType classType, IASTNode point) {
		return getPureVirtualMethods(classType);
	}
	
	/**
	 * Returns whether a problem binding represents a name resolution error due to an unknown built-in.
	 * Importantly, this will not return true for a misuse of a known builtin, which we want to diagnose.
	 * @param binding The problem binding to test.
	 * @param node Any node in the AST. Used to access the AST root.
	 * @since 6.3
	 */
	public static boolean isUnknownBuiltin(IProblemBinding binding, IASTNode node) {
		char[] name = binding.getNameCharArray();
		boolean isBuiltin = binding.getID() == IProblemBinding.SEMANTIC_NAME_NOT_FOUND &&
				CharArrayUtils.startsWith(name, "__builtin_");  //$NON-NLS-1$
		if (isBuiltin) {
			if (node != null) {
				IASTTranslationUnit tu = node.getTranslationUnit();
				if (tu instanceof ASTTranslationUnit) {
					return !((ASTTranslationUnit) tu).isKnownBuiltin(name);
				}
			}
			return true;	
		}
		return false;
	}
}

Back to the top