blob: 5c7323936f68b5f3dc7c0dccc96f14a0fe63b054 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2014 QNX Software Systems and others.
* 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:
* QNX - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Anton Leherbauer (Wind River Systems)
* Sergey Prigogin (Google)
* Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
* Nathan Ridge
* Thomas Corbat (IFS)
*******************************************************************************/
package org.eclipse.cdt.internal.ui.text.contentassist;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.swt.graphics.Image;
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTCompletionContext;
import org.eclipse.cdt.core.dom.ast.IASTCompletionNode;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionStyleMacroParameter;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorFunctionStyleMacroDefinition;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
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.IParameter;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.c.ICFunctionScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
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.ICPPBlockScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplatePartialSpecialization;
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.ICPPField;
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.ICPPMember;
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.ICPPParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.core.parser.util.IContentAssistMatcher;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.text.ICPartitions;
import org.eclipse.cdt.internal.core.dom.parser.c.CBuiltinParameter;
import org.eclipse.cdt.internal.core.dom.parser.c.CBuiltinVariable;
import org.eclipse.cdt.internal.core.dom.parser.c.CImplicitFunction;
import org.eclipse.cdt.internal.core.dom.parser.c.CImplicitTypedef;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBuiltinParameter;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBuiltinVariable;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitMethod;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitTypedef;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.AccessContext;
import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory;
import org.eclipse.cdt.internal.ui.viewsupport.CElementImageProvider;
/**
* Searches the DOM (both the AST and the index) for completion proposals.
*
* @author Bryan Wilkinson
*/
public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer {
private static final String HASH = "#"; //$NON-NLS-1$;
private static final String DEFAULT_ARGUMENT_PATTERN = " = {0}"; //$NON-NLS-1$;
private static final String TEMPLATE_PARAMETER_PATTERN = "template<{0}> class"; //$NON-NLS-1$;
private static final String TYPENAME = "typename"; //$NON-NLS-1$;
private static final String ELLIPSIS = "..."; //$NON-NLS-1$;
/**
* Default constructor is required (executable extension).
*/
public DOMCompletionProposalComputer() {
}
@Override
protected List<ICompletionProposal> computeCompletionProposals(
CContentAssistInvocationContext context,
IASTCompletionNode completionNode, String prefix) {
List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
if (inPreprocessorDirective(context)) {
if (!inPreprocessorKeyword(context)) {
// add only macros
if (prefix.length() == 0) {
try {
prefix= context.computeIdentifierPrefix().toString();
} catch (BadLocationException exc) {
CUIPlugin.log(exc);
}
}
addMacroProposals(context, prefix, proposals);
}
} else {
boolean handleMacros= false;
IASTName[] names = completionNode.getNames();
for (IASTName name : names) {
if (name.getTranslationUnit() == null)
// The node isn't properly hooked up, must have backtracked out of this node
continue;
IASTCompletionContext astContext = name.getCompletionContext();
if (astContext == null) {
continue;
} else if (astContext instanceof IASTIdExpression
|| astContext instanceof IASTNamedTypeSpecifier) {
// handle macros only if there is a prefix
handleMacros = prefix.length() > 0;
}
IBinding[] bindings = astContext.findBindings(name, !context.isContextInformationStyle());
if (bindings != null) {
AccessContext accessibilityContext = new AccessContext(name);
for (IBinding binding : bindings) {
if (accessibilityContext.isAccessible(binding))
handleBinding(binding, context, prefix, astContext, proposals);
}
}
}
if (handleMacros)
addMacroProposals(context, prefix, proposals);
}
return proposals;
}
/**
* Test whether the invocation offset is inside or before the preprocessor directive keyword.
*
* @param context the invocation context
* @return <code>true</code> if the invocation offset is inside or before the directive keyword
*/
private boolean inPreprocessorKeyword(CContentAssistInvocationContext context) {
IDocument doc = context.getDocument();
int offset = context.getInvocationOffset();
try {
final ITypedRegion partition=
TextUtilities.getPartition(doc, ICPartitions.C_PARTITIONING, offset, true);
if (ICPartitions.C_PREPROCESSOR.equals(partition.getType())) {
String ppPrefix= doc.get(partition.getOffset(), offset - partition.getOffset());
if (ppPrefix.matches("\\s*#\\s*\\w*")) { //$NON-NLS-1$
// we are inside the directive keyword
return true;
}
}
} catch (BadLocationException exc) {
}
return false;
}
/**
* Check if the invocation offset is inside a preprocessor directive.
*
* @param context the content asist invocation context
* @return <code>true</code> if invocation offset is inside a preprocessor directive
*/
private boolean inPreprocessorDirective(CContentAssistInvocationContext context) {
IDocument doc = context.getDocument();
int offset = context.getInvocationOffset();
try {
final ITypedRegion partition=
TextUtilities.getPartition(doc, ICPartitions.C_PARTITIONING, offset, true);
if (ICPartitions.C_PREPROCESSOR.equals(partition.getType())) {
return true;
}
} catch (BadLocationException exc) {
}
return false;
}
private void addMacroProposals(CContentAssistInvocationContext context, String prefix,
List<ICompletionProposal> proposals) {
IASTCompletionNode completionNode = context.getCompletionNode();
addMacroProposals(context, prefix, proposals,
completionNode.getTranslationUnit().getMacroDefinitions());
addMacroProposals(context, prefix, proposals,
completionNode.getTranslationUnit().getBuiltinMacroDefinitions());
}
private void addMacroProposals(CContentAssistInvocationContext context, String prefix,
List<ICompletionProposal> proposals, IASTPreprocessorMacroDefinition[] macros) {
if (macros != null) {
char[] prefixChars= prefix.toCharArray();
final boolean matchPrefix= !context.isContextInformationStyle();
if (matchPrefix) {
IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(prefixChars);
for (int i = 0; i < macros.length; ++i) {
final char[] macroName= macros[i].getName().toCharArray();
if (matcher.match(macroName)) {
handleMacro(macros[i], context, prefix, proposals);
}
}
} else {
for (int i = 0; i < macros.length; ++i) {
final char[] macroName= macros[i].getName().toCharArray();
if (CharArrayUtils.equals(macroName, 0, macroName.length, prefixChars, true)) {
handleMacro(macros[i], context, prefix, proposals);
}
}
}
}
}
private void handleMacro(IASTPreprocessorMacroDefinition macro, CContentAssistInvocationContext context,
String prefix, List<ICompletionProposal> proposals) {
final String macroName = macro.getName().toString();
final int baseRelevance= computeBaseRelevance(prefix, macroName);
Image image = getImage(CElementImageProvider.getMacroImageDescriptor());
if (macro instanceof IASTPreprocessorFunctionStyleMacroDefinition) {
IASTPreprocessorFunctionStyleMacroDefinition functionMacro =
(IASTPreprocessorFunctionStyleMacroDefinition) macro;
StringBuilder repStringBuff = new StringBuilder();
repStringBuff.append(macroName);
repStringBuff.append('(');
StringBuilder args = new StringBuilder();
IASTFunctionStyleMacroParameter[] params = functionMacro.getParameters();
if (params != null) {
final String parameterDelimiter = context.getFunctionParameterDelimiter();
for (int i = 0; i < params.length; ++i) {
if (i > 0) {
args.append(parameterDelimiter);
}
args.append(params[i].getParameter());
}
}
String argString = args.toString();
StringBuilder descStringBuff = new StringBuilder(repStringBuff.toString());
descStringBuff.append(argString);
descStringBuff.append(')');
repStringBuff.append(')');
String repString = repStringBuff.toString();
String descString = descStringBuff.toString();
CCompletionProposal proposal = createProposal(repString, descString, prefix.length(), image,
baseRelevance + RelevanceConstants.MACRO_TYPE_RELEVANCE, context);
if (!context.isContextInformationStyle()) {
if (argString.length() > 0) {
proposal.setCursorPosition(repString.length() - 1);
} else {
proposal.setCursorPosition(repString.length());
}
}
if (argString.length() > 0) {
CProposalContextInformation info = new CProposalContextInformation(image, descString, argString);
info.setContextInformationPosition(context.getContextInformationOffset());
proposal.setContextInformation(info);
}
proposals.add(proposal);
} else {
proposals.add(createProposal(macroName, macroName, prefix.length(), image,
baseRelevance + RelevanceConstants.MACRO_TYPE_RELEVANCE, context));
}
}
protected void handleBinding(IBinding binding, CContentAssistInvocationContext cContext, String prefix,
IASTCompletionContext astContext, List<ICompletionProposal> proposals) {
if ((binding instanceof CPPImplicitFunction
|| binding instanceof CPPImplicitTypedef
|| binding instanceof CPPBuiltinVariable
|| binding instanceof CPPBuiltinParameter
|| binding instanceof CImplicitFunction
|| binding instanceof CImplicitTypedef
|| binding instanceof CBuiltinVariable
|| binding instanceof CBuiltinParameter
|| binding instanceof ICPPClassTemplatePartialSpecialization)
&& !(binding instanceof CPPImplicitMethod)) {
return;
}
if (!isAnonymousBinding(binding)) {
final String name = binding.getName();
final int baseRelevance= computeBaseRelevance(prefix, name);
if (binding instanceof ICPPClassType) {
handleClass((ICPPClassType) binding, astContext, cContext, baseRelevance, proposals);
} else if (binding instanceof IFunction) {
handleFunction((IFunction) binding, cContext, baseRelevance, proposals);
} else if (binding instanceof IVariable) {
handleVariable((IVariable) binding, cContext, baseRelevance, proposals);
} else if (!cContext.isContextInformationStyle()) {
if (binding instanceof ITypedef) {
proposals.add(createProposal(name, name, getImage(binding),
baseRelevance + RelevanceConstants.TYPEDEF_TYPE_RELEVANCE, cContext));
} else if (binding instanceof ICPPNamespace) {
handleNamespace((ICPPNamespace) binding, astContext, cContext, baseRelevance, proposals);
} else if (binding instanceof IEnumeration) {
proposals.add(createProposal(name, name, getImage(binding),
baseRelevance + RelevanceConstants.ENUMERATION_TYPE_RELEVANCE, cContext));
} else if (binding instanceof IEnumerator) {
proposals.add(createProposal(name, name, getImage(binding),
baseRelevance + RelevanceConstants.ENUMERATOR_TYPE_RELEVANCE, cContext));
} else {
proposals.add(createProposal(name, name, getImage(binding),
baseRelevance + RelevanceConstants.DEFAULT_TYPE_RELEVANCE, cContext));
}
}
}
}
private boolean isAnonymousBinding(IBinding binding) {
char[] name= binding.getNameCharArray();
return name.length == 0 || name[0] == '{';
}
private void addProposalForClassTemplate(ICPPClassTemplate templateType, CContentAssistInvocationContext context,
int baseRelevance, List<ICompletionProposal> proposals) {
int relevance = getClassTypeRelevance(templateType);
StringBuilder representation = new StringBuilder(templateType.getName());
boolean inUsingDeclaration = context.isInUsingDirective();
String templateParameterRepresentation = ""; //$NON-NLS-1$
if (!inUsingDeclaration) {
representation.append("<{0}>"); //$NON-NLS-1$
templateParameterRepresentation = buildTemplateParameters(templateType, context);
} else if (!context.isFollowedBySemicolon()) {
representation.append(';');
}
String representationString = MessageFormat.format(representation.toString(), ""); //$NON-NLS-1$
String displayString = MessageFormat.format(representation.toString(), templateParameterRepresentation);
CCompletionProposal proposal = createProposal(representationString, displayString, getImage(templateType),
baseRelevance + relevance, context);
if (!inUsingDeclaration) {
CProposalContextInformation info =
new CProposalContextInformation(getImage(templateType), displayString, templateParameterRepresentation);
info.setContextInformationPosition(context.getContextInformationOffset());
proposal.setContextInformation(info);
if (!context.isContextInformationStyle()) {
proposal.setCursorPosition(representationString.length() - 1);
}
}
proposals.add(proposal);
}
private String buildTemplateParameters(ICPPClassTemplate templateType, CContentAssistInvocationContext context) {
ICPPTemplateParameter[] parameters = templateType.getTemplateParameters();
StringBuilder representation = new StringBuilder();
final String parameterDelimiter = context.getTemplateParameterDelimiter();
final boolean addDefaultedParameters = isDisplayDefaultedParameters();
final boolean addDefaultArguments = isDisplayDefaultArguments();
for (int i = 0; i < parameters.length; i++) {
ICPPTemplateParameter parameter = parameters[i];
ICPPTemplateArgument defaultValue = parameter.getDefaultValue();
if (!addDefaultedParameters && defaultValue != null) {
break;
}
if (i > 0) {
representation.append(parameterDelimiter);
}
if (parameter instanceof ICPPTemplateNonTypeParameter) {
IType parameterType = ((ICPPTemplateNonTypeParameter) parameter).getType();
String typeName = ASTTypeUtil.getType(parameterType);
representation.append(typeName);
} else if (parameter instanceof ICPPTemplateTypeParameter) {
representation.append(TYPENAME);
} else if (parameter instanceof ICPPTemplateTemplateParameter) {
String templateParameterParameters = buildTemplateParameters((ICPPTemplateTemplateParameter) parameter, context);
representation.append(MessageFormat.format(TEMPLATE_PARAMETER_PATTERN, templateParameterParameters));
representation.append(templateParameterParameters);
}
if (parameter.isParameterPack()) {
representation.append(ELLIPSIS);
}
representation.append(' ');
representation.append(parameter.getName());
if (addDefaultArguments && defaultValue != null) {
String defaultArgumentRepresentation = MessageFormat.format(DEFAULT_ARGUMENT_PATTERN, defaultValue);
for (int parameterIndex = 0; parameterIndex < i; parameterIndex++) {
String templateArgumentID = HASH + parameterIndex;
String templateArgumentValue = parameters[parameterIndex].getName();
defaultArgumentRepresentation = defaultArgumentRepresentation.replaceAll(templateArgumentID, templateArgumentValue);
}
representation.append(defaultArgumentRepresentation);
}
}
return representation.toString();
}
private void handleClass(ICPPClassType classType, IASTCompletionContext astContext,
CContentAssistInvocationContext context, int baseRelevance, List<ICompletionProposal> proposals) {
if (context.isContextInformationStyle() && context.isAfterOpeningParenthesis()) {
addProposalsForConstructors(classType, context, baseRelevance, proposals);
} else if (classType instanceof ICPPClassTemplate) {
addProposalForClassTemplate((ICPPClassTemplate) classType, context, baseRelevance, proposals);
} else {
int relevance = getClassTypeRelevance(classType);
if (astContext instanceof IASTName && !(astContext instanceof ICPPASTQualifiedName)) {
IASTName name= (IASTName)astContext;
if (name.getParent() instanceof IASTDeclarator) {
proposals.add(createProposal(classType.getName() + "::", classType.getName(), //$NON-NLS-1$
getImage(classType), baseRelevance + relevance, context));
}
}
proposals.add(createProposal(classType.getName(), classType.getName(), getImage(classType),
baseRelevance + RelevanceConstants.CLASS_TYPE_RELEVANCE, context));
}
}
private void addProposalsForConstructors(ICPPClassType classType,
CContentAssistInvocationContext context, int baseRelevance, List<ICompletionProposal> proposals) {
ICPPConstructor[] constructors = classType.getConstructors();
for (ICPPConstructor constructor : constructors) {
handleFunction(constructor, context, baseRelevance, proposals);
}
}
private int getClassTypeRelevance(ICPPClassType classType) {
int relevance= 0;
switch (classType.getKey()) {
case ICPPClassType.k_class:
relevance= RelevanceConstants.CLASS_TYPE_RELEVANCE;
break;
case ICompositeType.k_struct:
relevance= RelevanceConstants.STRUCT_TYPE_RELEVANCE;
break;
case ICompositeType.k_union:
relevance= RelevanceConstants.UNION_TYPE_RELEVANCE;
break;
}
return relevance;
}
private void handleFunction(IFunction function, CContentAssistInvocationContext context,
int baseRelevance, List<ICompletionProposal> proposals) {
Image image = getImage(function);
StringBuilder repStringBuff = new StringBuilder();
repStringBuff.append(function.getName());
repStringBuff.append('(');
StringBuilder dispargs = new StringBuilder(); // for the dispargString
StringBuilder idargs = new StringBuilder(); // for the idargString
boolean hasArgs = true;
String returnTypeStr = null;
IParameter[] params = function.getParameters();
if (params != null) {
final String parameterDelimiter = context.getFunctionParameterDelimiter();
for (int i = 0; i < params.length; ++i) {
IParameter param = params[i];
if (skipDefaultedParameter(param)) {
break;
}
IType paramType = param.getType();
if (i > 0) {
dispargs.append(parameterDelimiter);
idargs.append(parameterDelimiter);
}
dispargs.append(ASTTypeUtil.getType(paramType, false));
idargs.append(ASTTypeUtil.getType(paramType, false));
String paramName = param.getName();
if (paramName != null && paramName.length() > 0) {
dispargs.append(' ');
dispargs.append(paramName);
}
if (param instanceof ICPPParameter) {
ICPPParameter cppParam = (ICPPParameter) param;
if (cppParam.hasDefaultValue() && isDisplayDefaultArguments()) {
dispargs.append(MessageFormat.format(DEFAULT_ARGUMENT_PATTERN, cppParam.getDefaultValue()));
}
}
}
if (function.takesVarArgs()) {
if (params.length > 0) {
dispargs.append(parameterDelimiter);
idargs.append(parameterDelimiter);
}
dispargs.append("..."); //$NON-NLS-1$
idargs.append("..."); //$NON-NLS-1$
} else if (params.length == 0) { // force the void in
dispargs.append("void"); //$NON-NLS-1$
idargs.append("void"); //$NON-NLS-1$
}
}
IFunctionType functionType = function.getType();
if (functionType != null) {
IType returnType = functionType.getReturnType();
if (returnType != null)
returnTypeStr = ASTTypeUtil.getType(returnType, false);
}
hasArgs = ASTTypeUtil.functionTakesParameters(function);
String dispargString = dispargs.toString();
String idargString = idargs.toString();
String contextDispargString = hasArgs ? dispargString : null;
StringBuilder dispStringBuff = new StringBuilder(repStringBuff.toString());
dispStringBuff.append(dispargString);
dispStringBuff.append(')');
if (returnTypeStr != null && returnTypeStr.length() > 0) {
dispStringBuff.append(" : "); //$NON-NLS-1$
dispStringBuff.append(returnTypeStr);
}
String dispString = dispStringBuff.toString();
StringBuilder idStringBuff = new StringBuilder(repStringBuff.toString());
idStringBuff.append(idargString);
idStringBuff.append(')');
String idString = idStringBuff.toString();
// In a using declaration, emitting parentheses after the function
// name is useless, since the user will just have to delete them.
// Instead, emitting a semicolon is useful.
boolean inUsingDeclaration = context.isInUsingDirective();
if (inUsingDeclaration) {
repStringBuff.setLength(repStringBuff.length() - 1); // Remove opening parenthesis
if (!context.isFollowedBySemicolon()) {
repStringBuff.append(';');
}
} else {
repStringBuff.append(')');
}
String repString = repStringBuff.toString();
final int relevance = function instanceof ICPPMethod ?
RelevanceConstants.METHOD_TYPE_RELEVANCE : RelevanceConstants.FUNCTION_TYPE_RELEVANCE;
CCompletionProposal proposal = createProposal(repString, dispString, idString,
context.getCompletionNode().getLength(), image, baseRelevance + relevance, context);
if (!context.isContextInformationStyle()) {
int cursorPosition = (!inUsingDeclaration && hasArgs) ? (repString.length() - 1) : repString.length();
proposal.setCursorPosition(cursorPosition);
}
if (contextDispargString != null && !inUsingDeclaration) {
CProposalContextInformation info =
new CProposalContextInformation(image, dispString, contextDispargString);
info.setContextInformationPosition(context.getContextInformationOffset());
proposal.setContextInformation(info);
}
proposals.add(proposal);
}
private boolean skipDefaultedParameter(IParameter param) {
return !isDisplayDefaultedParameters() && param instanceof ICPPParameter && ((ICPPParameter)param).hasDefaultValue();
}
private void handleVariable(IVariable variable, CContentAssistInvocationContext context,
int baseRelevance, List<ICompletionProposal> proposals) {
if (context.isContextInformationStyle()) {
IType t = variable.getType();
t= unwindTypedefs(t);
if (t instanceof ICPPClassType) {
ICPPClassType classType= (ICPPClassType) t;
IASTTranslationUnit ast = context.getCompletionNode().getTranslationUnit();
ICPPConstructor[] constructors = ClassTypeHelper.getConstructors(classType, ast);
for (ICPPConstructor constructor : constructors) {
handleFunction(constructor, context, baseRelevance, proposals);
}
}
return;
}
StringBuilder repStringBuff = new StringBuilder();
repStringBuff.append(variable.getName());
String returnTypeStr = "<unknown>"; //$NON-NLS-1$
IType varType = variable.getType();
if (varType != null)
returnTypeStr = ASTTypeUtil.getType(varType, false);
StringBuilder dispStringBuff = new StringBuilder(repStringBuff.toString());
if (returnTypeStr != null) {
dispStringBuff.append(" : "); //$NON-NLS-1$
dispStringBuff.append(returnTypeStr);
}
String dispString = dispStringBuff.toString();
StringBuilder idStringBuff = new StringBuilder(repStringBuff.toString());
String idString = idStringBuff.toString();
String repString = repStringBuff.toString();
Image image = getImage(variable);
final int relevance = isLocalVariable(variable) ?
RelevanceConstants.LOCAL_VARIABLE_TYPE_RELEVANCE :
isField(variable) ?
RelevanceConstants.FIELD_TYPE_RELEVANCE :
RelevanceConstants.VARIABLE_TYPE_RELEVANCE;
CCompletionProposal proposal = createProposal(repString, dispString, idString,
context.getCompletionNode().getLength(), image, baseRelevance + relevance, context);
proposals.add(proposal);
}
private IType unwindTypedefs(final IType t) {
IType r= t;
while (r instanceof ITypedef) {
r= ((ITypedef) r).getType();
}
return r != null ? r : t;
}
private static boolean isField(IVariable variable) {
return variable instanceof IField;
}
private static boolean isLocalVariable(IVariable variable) {
try {
return isLocalScope(variable.getScope());
} catch (DOMException exc) {
return false;
}
}
private static boolean isLocalScope(IScope scope) {
while (scope != null) {
if (scope instanceof ICPPFunctionScope ||
scope instanceof ICPPBlockScope ||
scope instanceof ICFunctionScope) {
return true;
}
try {
scope= scope.getParent();
} catch (DOMException e) {
scope= null;
}
}
return false;
}
private void handleNamespace(ICPPNamespace namespace, IASTCompletionContext astContext,
CContentAssistInvocationContext cContext, int baseRelevance,
List<ICompletionProposal> proposals) {
if (astContext instanceof ICPPASTQualifiedName) {
IASTCompletionContext parent = ((ICPPASTQualifiedName) astContext)
.getCompletionContext();
handleNamespace(namespace, parent, cContext, baseRelevance, proposals);
return;
}
StringBuilder repStringBuff = new StringBuilder();
repStringBuff.append(namespace.getName());
if (!(astContext instanceof ICPPASTUsingDeclaration)
&& !(astContext instanceof ICPPASTUsingDirective)) {
repStringBuff.append("::"); //$NON-NLS-1$
}
String repString = repStringBuff.toString();
proposals.add(createProposal(repString, namespace.getName(), getImage(namespace),
baseRelevance + RelevanceConstants.NAMESPACE_TYPE_RELEVANCE, cContext));
}
private CCompletionProposal createProposal(String repString, String dispString, Image image,
int relevance, CContentAssistInvocationContext context) {
return createProposal(repString, dispString, null, context.getCompletionNode().getLength(), image,
relevance, context);
}
private CCompletionProposal createProposal(String repString, String dispString, int prefixLength,
Image image, int relevance, CContentAssistInvocationContext context) {
return createProposal(repString, dispString, null, prefixLength, image, relevance, context);
}
private CCompletionProposal createProposal(String repString, String dispString, String idString,
int prefixLength, Image image, int relevance, CContentAssistInvocationContext context) {
int parseOffset = context.getParseOffset();
int invocationOffset = context.getInvocationOffset();
boolean doReplacement = !context.isContextInformationStyle();
int repLength = doReplacement ? prefixLength : 0;
int repOffset = doReplacement ? parseOffset - repLength : invocationOffset;
repString = doReplacement ? repString : ""; //$NON-NLS-1$
return new CCompletionProposal(repString, repOffset, repLength, image, dispString, idString,
relevance, context.getViewer());
}
private Image getImage(ImageDescriptor desc) {
return desc != null ? CUIPlugin.getImageDescriptorRegistry().get(desc) : null;
}
private Image getImage(IBinding binding) {
ImageDescriptor imageDescriptor = null;
if (binding instanceof ITypedef) {
imageDescriptor = CElementImageProvider.getTypedefImageDescriptor();
} else if (binding instanceof ICompositeType) {
if (((ICompositeType)binding).getKey() == ICPPClassType.k_class || binding instanceof ICPPClassTemplate)
imageDescriptor = CElementImageProvider.getClassImageDescriptor();
else if (((ICompositeType)binding).getKey() == ICompositeType.k_struct)
imageDescriptor = CElementImageProvider.getStructImageDescriptor();
else if (((ICompositeType)binding).getKey() == ICompositeType.k_union)
imageDescriptor = CElementImageProvider.getUnionImageDescriptor();
} else if (binding instanceof ICPPMethod) {
switch (((ICPPMethod)binding).getVisibility()) {
case ICPPMember.v_private:
imageDescriptor = CElementImageProvider.getMethodImageDescriptor(ASTAccessVisibility.PRIVATE);
break;
case ICPPMember.v_protected:
imageDescriptor = CElementImageProvider.getMethodImageDescriptor(ASTAccessVisibility.PROTECTED);
break;
default:
imageDescriptor = CElementImageProvider.getMethodImageDescriptor(ASTAccessVisibility.PUBLIC);
break;
}
} else if (binding instanceof IFunction) {
imageDescriptor = CElementImageProvider.getFunctionImageDescriptor();
} else if (binding instanceof ICPPField) {
switch (((ICPPField)binding).getVisibility()) {
case ICPPMember.v_private:
imageDescriptor = CElementImageProvider.getFieldImageDescriptor(ASTAccessVisibility.PRIVATE);
break;
case ICPPMember.v_protected:
imageDescriptor = CElementImageProvider.getFieldImageDescriptor(ASTAccessVisibility.PROTECTED);
break;
default:
imageDescriptor = CElementImageProvider.getFieldImageDescriptor(ASTAccessVisibility.PUBLIC);
break;
}
} else if (binding instanceof IField) {
imageDescriptor = CElementImageProvider.getFieldImageDescriptor(ASTAccessVisibility.PUBLIC);
} else if (binding instanceof IVariable) {
imageDescriptor = CElementImageProvider.getVariableImageDescriptor();
} else if (binding instanceof IEnumeration) {
imageDescriptor = CElementImageProvider.getEnumerationImageDescriptor();
} else if (binding instanceof IEnumerator) {
imageDescriptor = CElementImageProvider.getEnumeratorImageDescriptor();
} else if (binding instanceof ICPPNamespace) {
imageDescriptor = CElementImageProvider.getNamespaceImageDescriptor();
} else if (binding instanceof ICPPFunctionTemplate) {
imageDescriptor = CElementImageProvider.getFunctionImageDescriptor();
} else if (binding instanceof ICPPUsingDeclaration) {
IBinding[] delegates = ((ICPPUsingDeclaration) binding).getDelegates();
if (delegates.length > 0)
return getImage(delegates[0]);
}
return imageDescriptor != null ?
CUIPlugin.getImageDescriptorRegistry().get(imageDescriptor) : null;
}
private static boolean isDisplayDefaultArguments() {
IPreferenceStore preferenceStore = getPreferenceStore();
return preferenceStore.getBoolean(ContentAssistPreference.DEFAULT_ARGUMENT_DISPLAY_ARGUMENTS);
}
private static boolean isDisplayDefaultedParameters() {
IPreferenceStore preferenceStore = getPreferenceStore();
return preferenceStore.getBoolean(ContentAssistPreference.DEFAULT_ARGUMENT_DISPLAY_PARAMETERS_WITH_DEFAULT_ARGUMENT);
}
private static IPreferenceStore getPreferenceStore() {
return CUIPlugin.getDefault().getPreferenceStore();
}
}