From 1908efec3811e8c24030a5b38140b00fbb66ca61 Mon Sep 17 00:00:00 2001 From: Andrew Eidsness Date: Wed, 20 Feb 2013 13:23:40 -0500 Subject: [PATCH] qt slot/signal auto-complete Tags signal and slot methods when the index is created. Uses these tags to suggest values inside of SIGNAL and SLOT macro expansions. Enabled only for projects with the QtNature. Recognizes QObject::connect function calls and suggests SIGNAL(a) and SLOT(a) for the 2nd and 4th parameters. When expanding the SIGNAL and SLOT macros within a call to QObject::connect, suggests signals and slots based on the type of the previous parameter. E.g. in QObjectA a; QObjectB b; QObject::connect( &a, SIGNAL(*), &b, SLOT(**) ); The content assistant will suggest the methods of type QObjectA that have been marked as signals at *, and the methods of QObjectB that have been marked as slots at **. Change-Id: Ia6aaa71724547b0977e322399a500f072004767a Reviewed-on: https://git.eclipse.org/r/10532 Reviewed-by: Doug Schaefer IP-Clean: Doug Schaefer Tested-by: Doug Schaefer --- .../META-INF/MANIFEST.MF | 2 +- qt/org.eclipse.cdt.qt.core/plugin.xml | 16 + .../org/eclipse/cdt/qt/core/Activator.java | 30 -- .../org/eclipse/cdt/qt/core/QtKeywords.java | 6 + .../src/org/eclipse/cdt/qt/core/QtPlugin.java | 38 ++ .../qt/internal/core/QtSignalSlotTagger.java | 101 +++++ qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF | 6 +- qt/org.eclipse.cdt.qt.ui/plugin.xml | 12 + .../ui/QtCompletionProposalComputer.java | 392 ++++++++++++++++++ .../qt/ui/{Activator.java => QtUIPlugin.java} | 8 +- 10 files changed, 574 insertions(+), 37 deletions(-) delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/Activator.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtPlugin.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtSignalSlotTagger.java create mode 100644 qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java rename qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/{Activator.java => QtUIPlugin.java} (85%) diff --git a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF index 67bb08fb6ca..31d4aeefd56 100644 --- a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF +++ b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: CDT Qt Support Core Bundle-SymbolicName: org.eclipse.cdt.qt.core;singleton:=true Bundle-Version: 1.0.0.qualifier -Bundle-Activator: org.eclipse.cdt.qt.core.Activator +Bundle-Activator: org.eclipse.cdt.qt.core.QtPlugin Bundle-Vendor: Eclipse CDT Require-Bundle: org.eclipse.core.runtime, org.eclipse.core.resources, diff --git a/qt/org.eclipse.cdt.qt.core/plugin.xml b/qt/org.eclipse.cdt.qt.core/plugin.xml index 959e78450a5..d31e961af1d 100644 --- a/qt/org.eclipse.cdt.qt.core/plugin.xml +++ b/qt/org.eclipse.cdt.qt.core/plugin.xml @@ -50,4 +50,20 @@ + + + + + + + + + + + diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/Activator.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/Activator.java deleted file mode 100644 index 2e3a4ecd3a4..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/Activator.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.eclipse.cdt.qt.core; - -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; - -public class Activator implements BundleActivator { - - private static BundleContext context; - - static BundleContext getContext() { - return context; - } - - /* - * (non-Javadoc) - * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) - */ - public void start(BundleContext bundleContext) throws Exception { - Activator.context = bundleContext; - } - - /* - * (non-Javadoc) - * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) - */ - public void stop(BundleContext bundleContext) throws Exception { - Activator.context = null; - } - -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtKeywords.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtKeywords.java index 36b2112585d..381655ef025 100644 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtKeywords.java +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtKeywords.java @@ -17,4 +17,10 @@ public class QtKeywords public static final String Q_SLOTS = "Q_SLOTS"; public static final String SIGNALS = "signals"; public static final String SLOTS = "slots"; + + public static final String SIGNAL = "SIGNAL"; + public static final String SLOT = "SLOT"; + + public static final String QOBJECT = "QObject"; + public static final String CONNECT = "connect"; } diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtPlugin.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtPlugin.java new file mode 100644 index 00000000000..825b5614cc7 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtPlugin.java @@ -0,0 +1,38 @@ +package org.eclipse.cdt.qt.core; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class QtPlugin implements BundleActivator { + + public static final String ID = "org.eclipse.cdt.qt.core"; + public static final String SIGNAL_SLOT_TAGGER_ID = ID + ".signalslot.tagger"; + + public static final int SignalSlot_Mask_signal = 1; + public static final int SignalSlot_Mask_slot = 2; + + private static BundleContext context; + + static BundleContext getContext() { + return context; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext bundleContext) throws Exception { + QtPlugin.context = bundleContext; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext bundleContext) throws Exception { + QtPlugin.context = null; + } + +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtSignalSlotTagger.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtSignalSlotTagger.java new file mode 100644 index 00000000000..a82b3c15547 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtSignalSlotTagger.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2013 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 + */ + +package org.eclipse.cdt.qt.internal.core; + +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.tag.IBindingTagger; +import org.eclipse.cdt.core.dom.ast.tag.ITag; +import org.eclipse.cdt.core.dom.ast.tag.ITagWriter; +import org.eclipse.cdt.core.dom.ast.tag.IWritableTag; +import org.eclipse.cdt.qt.core.QtKeywords; +import org.eclipse.cdt.qt.core.QtPlugin; + +public class QtSignalSlotTagger implements IBindingTagger +{ + private static ICPPASTVisibilityLabel findVisibilityLabel( ICPPMethod method, IASTNode ast ) + { + // the visibility cannot be found without an ast + if( ast == null ) + return null; + + IASTNode methodDecl = ast; + ICPPASTCompositeTypeSpecifier classType = null; + while( methodDecl != null + && classType == null ) + { + IASTNode parent = methodDecl.getParent(); + if( parent instanceof ICPPASTCompositeTypeSpecifier ) + classType = (ICPPASTCompositeTypeSpecifier)parent; + else + methodDecl = parent; + } + + if( methodDecl == null + || classType == null ) + return null; + + ICPPASTVisibilityLabel lastLabel = null; + for( IASTDeclaration decl : classType.getMembers() ) + { + if( decl instanceof ICPPASTVisibilityLabel ) + lastLabel = (ICPPASTVisibilityLabel)decl; + else if( decl == methodDecl ) + return lastLabel; + } + + return null; + } + + @Override + public ITag process( ITagWriter tagWriter, IBinding binding, IASTName ast ) + { + // only methods a be signals or slots + if( ! ( binding instanceof ICPPMethod ) ) + return null; + + // a visibility label is required in order to decide whether the method is a signal/slot + ICPPMethod method = (ICPPMethod)binding; + ICPPASTVisibilityLabel v = findVisibilityLabel( method, ast ); + if( v == null ) + return null; + + byte bitset = 0; + for( IASTNodeLocation loc : v.getNodeLocations() ) + if( loc instanceof IASTMacroExpansionLocation ) + { + IASTMacroExpansionLocation macroExpansion = (IASTMacroExpansionLocation)loc; + IASTPreprocessorMacroExpansion exp = macroExpansion.getExpansion(); + String macro = exp.getMacroReference().toString(); + + if( QtKeywords.SIGNALS.equals( macro ) || QtKeywords.Q_SIGNALS.equals( macro ) ) + bitset |= QtPlugin.SignalSlot_Mask_signal; + else if( QtKeywords.SLOTS.equals( macro ) || QtKeywords.Q_SLOTS.equals( macro ) ) + bitset |= QtPlugin.SignalSlot_Mask_slot; + } + + if( bitset != 0 ) + { + IWritableTag tag = tagWriter.createTag( QtPlugin.SIGNAL_SLOT_TAGGER_ID, 1 ); + if( tag != null + && tag.putByte( 0, bitset ) ) + return tag; + } + + return null; + } +} diff --git a/qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF b/qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF index 0e024d23ae1..856b83c6f2a 100644 --- a/qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF +++ b/qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF @@ -3,13 +3,15 @@ Bundle-ManifestVersion: 2 Bundle-Name: CDT Qt Support UI Bundle-SymbolicName: org.eclipse.cdt.qt.ui;singleton:=true Bundle-Version: 1.0.0.qualifier -Bundle-Activator: org.eclipse.cdt.qt.ui.Activator +Bundle-Activator: org.eclipse.cdt.qt.ui.QtUIPlugin Bundle-Vendor: Eclipse CDT Bundle-Localization: plugin Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, org.eclipse.cdt.ui, org.eclipse.cdt.core, - org.eclipse.cdt.qt.core + org.eclipse.cdt.qt.core, + org.eclipse.jface.text, + org.eclipse.core.resources Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy diff --git a/qt/org.eclipse.cdt.qt.ui/plugin.xml b/qt/org.eclipse.cdt.qt.ui/plugin.xml index 7d86d31f7c4..e03dd26e7ab 100644 --- a/qt/org.eclipse.cdt.qt.ui/plugin.xml +++ b/qt/org.eclipse.cdt.qt.ui/plugin.xml @@ -23,4 +23,16 @@ + + + + + + diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java new file mode 100644 index 00000000000..733e08857ab --- /dev/null +++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2013 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 + */ + +package org.eclipse.cdt.qt.internal.ui; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.ast.ASTTypeUtil; +import org.eclipse.cdt.core.dom.ast.IASTCompletionContext; +import org.eclipse.cdt.core.dom.ast.IASTCompletionNode; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; +import org.eclipse.cdt.core.dom.ast.IASTIdExpression; +import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IPointerType; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; +import org.eclipse.cdt.core.dom.ast.tag.ITag; +import org.eclipse.cdt.core.dom.ast.tag.ITagReader; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; +import org.eclipse.cdt.internal.ui.text.contentassist.CCompletionProposal; +import org.eclipse.cdt.internal.ui.text.contentassist.CContentAssistInvocationContext; +import org.eclipse.cdt.internal.ui.text.contentassist.ParsingBasedProposalComputer; +import org.eclipse.cdt.internal.ui.text.contentassist.RelevanceConstants; +import org.eclipse.cdt.qt.core.QtKeywords; +import org.eclipse.cdt.qt.core.QtNature; +import org.eclipse.cdt.qt.core.QtPlugin; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.contentassist.ICompletionProposal; + +@SuppressWarnings( "restriction" ) +public class QtCompletionProposalComputer extends ParsingBasedProposalComputer +{ + private boolean isApplicable( CContentAssistInvocationContext context ) + { + ITranslationUnit tu = context.getTranslationUnit(); + if( tu == null ) + return false; + + ICProject cProject = tu.getCProject(); + if( cProject == null ) + return false; + + IProject project = cProject.getProject(); + if( project == null ) + return false; + + try + { + return project.hasNature( QtNature.ID ); + } + catch( CoreException e ) + { + CUIPlugin.log( e ); + return false; + } + } + + private static boolean is_QObject_connect( CContentAssistInvocationContext context, IASTCompletionContext astContext, IASTName name ) + { + IASTName connectName = name.getLastName(); + if( ! QtKeywords.CONNECT.equals( new String( connectName.getSimpleID() ) ) ) + return false; + + IBinding[] funcBindings = astContext.findBindings( connectName, ! context.isContextInformationStyle() ); + for( IBinding funcBinding : funcBindings ) + if( funcBinding instanceof ICPPFunction ) + { + IBinding ownerBinding = ( (ICPPFunction)funcBinding ).getOwner(); + if( ownerBinding != null && QtKeywords.QOBJECT.equals( ownerBinding.getName() ) ) + return true; + } + + return false; + } + + private static class Completion + { + private final String replacement; + private final String display; + private final int cursorOffset; + + public static final Completion SIGNAL = new Completion( "SIGNAL()", "SIGNAL(a)", -1 ); + public static final Completion SLOT = new Completion( "SLOT()", "SLOT(a)", -1 ); + + public Completion( String replacement ) + { + this( replacement, replacement, 0 ); + } + + public Completion( String replacement, String display, int cursorOffset ) + { + this.replacement = replacement; + this.display = display; + this.cursorOffset = cursorOffset; + } + + public ICompletionProposal createProposal( CContentAssistInvocationContext context ) + { + int repLength = replacement.length(); + int repOffset = context.getInvocationOffset(); + CCompletionProposal p = new CCompletionProposal( replacement, repOffset, repLength, null, display, RelevanceConstants.DEFAULT_TYPE_RELEVANCE, context.getViewer() ); + p.setCursorPosition( repLength + cursorOffset ); + return p; + } + + @Override + public String toString() + { + if( replacement == null ) + return super.toString(); + return replacement + '@' + cursorOffset; + } + } + + private static interface MethodFilter + { + public boolean keep( ICPPMethod method ); + + public static class Qt + { + public static final MethodFilter Signal = new MethodFilter() + { + @Override + public boolean keep( ICPPMethod method ) + { + ITagReader tagReader = CCorePlugin.getTagService().findTagReader( method ); + if( tagReader == null ) + return false; + + ITag tag = tagReader.getTag( QtPlugin.SIGNAL_SLOT_TAGGER_ID ); + if( tag == null ) + return false; + + int result = tag.getByte( 0 ); + return result != ITag.Fail + && ( ( result & QtPlugin.SignalSlot_Mask_signal ) == QtPlugin.SignalSlot_Mask_signal ); + } + }; + + public static final MethodFilter Slot = new MethodFilter() + { + @Override + public boolean keep( ICPPMethod method ) + { + ITagReader tagReader = CCorePlugin.getTagService().findTagReader( method ); + if( tagReader == null ) + return false; + + ITag tag = tagReader.getTag( QtPlugin.SIGNAL_SLOT_TAGGER_ID ); + if( tag == null ) + return false; + + int result = tag.getByte( 0 ); + return result != ITag.Fail + && ( ( result & QtPlugin.SignalSlot_Mask_slot ) == QtPlugin.SignalSlot_Mask_slot ); + } + }; + } + } + + private static Iterable filterMethods( final ICPPClassType cls, final MethodFilter filter ) + { + return new Iterable() + { + @Override + public Iterator iterator() + { + return new Iterator() + { + private int index = 0; + private final ICPPMethod[] methods = cls.getMethods(); + + @Override + public boolean hasNext() + { + for( ; index < methods.length; ++index ) + if( filter.keep( methods[index] ) ) + return true; + return false; + } + + @Override public ICPPMethod next() { return methods[index++]; } + @Override public void remove() { } + }; + } + }; + } + + private static String getSignature( ICPPMethod method ) + { + StringBuilder signature = new StringBuilder(); + + signature.append( method.getName() ); + signature.append( '(' ); + boolean first = true; + for( ICPPParameter param : method.getParameters() ) + { + if( first ) + first = false; + else + signature.append( ", " ); + signature.append( ASTTypeUtil.getType( param.getType() ) ); + } + + signature.append( ')' ); + return signature.toString(); + } + + private static void addCompletionsFor( Collection completions, IASTInitializerClause init, MethodFilter filter ) + { + if( !( init instanceof ICPPASTInitializerClause ) ) + return; + + ICPPEvaluation eval = ( (ICPPASTInitializerClause)init ).getEvaluation(); + if( eval == null ) + return; + + IType type = eval.getTypeOrFunctionSet( init ); + while( type instanceof IPointerType ) + type = ( (IPointerType)type ).getType(); + + if( type instanceof ICPPClassType ) + for( ICPPMethod signal : filterMethods( (ICPPClassType)type, filter ) ) + completions.add( new Completion( getSignature( signal ) ) ); + } + + // Copied from org.eclipse.cdt.internal.ui.text.CParameterListValidator + private static int indexOfClosingPeer(String code, char left, char right, int pos) { + int level= 0; + final int length= code.length(); + while (pos < length) { + char ch= code.charAt(pos); + if (ch == left) { + ++level; + } else if (ch == right) { + if (--level == 0) { + return pos; + } + } + ++pos; + } + return -1; + } + + // Copied from org.eclipse.cdt.internal.ui.text.CParameterListValidator + private static int[] computeCommaPositions(String code) { + final int length= code.length(); + int pos= 0; + List positions= new ArrayList(); + positions.add(new Integer(-1)); + while (pos < length && pos != -1) { + char ch= code.charAt(pos); + switch (ch) { + case ',': + positions.add(new Integer(pos)); + break; + case '(': + pos= indexOfClosingPeer(code, '(', ')', pos); + break; + case '<': + pos= indexOfClosingPeer(code, '<', '>', pos); + break; + case '[': + pos= indexOfClosingPeer(code, '[', ']', pos); + break; + default: + break; + } + if (pos != -1) + pos++; + } + positions.add(new Integer(length)); + + int[] fields= new int[positions.size()]; + for (int i= 0; i < fields.length; i++) + fields[i]= positions.get(i).intValue(); + return fields; + } + + + private void addConnectParameterCompletions( List proposals, CContentAssistInvocationContext context, IASTCompletionNode completionNode, String prefix ) + { + IASTName[] names = completionNode.getNames(); + List completions = new LinkedList(); + + for( IASTName name : names ) + { + // The node isn't properly hooked up, must have backtracked out of this node + if( name.getTranslationUnit() == null ) + continue; + + IASTCompletionContext astContext = name.getCompletionContext(); + if( astContext == null || ! ( astContext instanceof IASTNode ) ) + continue; + IASTNode astNode = (IASTNode)astContext; + + if( is_QObject_connect( context, astContext, name ) ) + { + int parseOffset = context.getParseOffset(); + int invocationOffset = context.getInvocationOffset(); + + String unparsed = ""; + try { unparsed = context.getDocument().get( parseOffset, invocationOffset - parseOffset ); } + catch( BadLocationException e ) { CCorePlugin.log( e ); } + + if( unparsed.length() > 0 && unparsed.charAt( 0 ) == '(' ) + unparsed = unparsed.substring( 1 ); + + int[] commas = computeCommaPositions( unparsed ); + switch( commas.length ) + { + case 3: + completions.add( Completion.SIGNAL ); + break; + case 5: + completions.add( Completion.SLOT ); + break; + } + } + else if( astNode.getPropertyInParent() == IASTFunctionCallExpression.ARGUMENT ) + { + IASTNode parent = astNode.getParent(); + if( ! ( parent instanceof IASTFunctionCallExpression ) ) + continue; + IASTFunctionCallExpression call = (IASTFunctionCallExpression)parent; + IASTExpression nameExpr = call.getFunctionNameExpression(); + if( !( nameExpr instanceof IASTIdExpression ) ) + continue; + IASTIdExpression funcNameIdExpr = (IASTIdExpression)nameExpr; + IASTName funcName = funcNameIdExpr.getName(); + + if( !is_QObject_connect( context, astContext, funcName ) ) + continue; + + IASTInitializerClause[] args = call.getArguments(); + switch( args.length ) + { + case 2: + //if( QtKeywords.SIGNAL.equals( prefix ) ) + addCompletionsFor( completions, args[0], MethodFilter.Qt.Signal ); + break; + case 4: + if( QtKeywords.SLOT.equals( prefix ) ) + addCompletionsFor( completions, args[2], MethodFilter.Qt.Slot ); + break; + } + } + } + + for( Completion completion : completions ) + { + ICompletionProposal proposal = completion.createProposal( context ); + if( proposal != null ) + proposals.add( proposal ); + } + } + + @Override + protected List computeCompletionProposals( CContentAssistInvocationContext context, IASTCompletionNode completionNode, String prefix ) throws CoreException + { + if( !isApplicable( context ) ) + return Collections.emptyList(); + + List proposals = new ArrayList(); + addConnectParameterCompletions( proposals, context, completionNode, prefix ); + return proposals; + } +} diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/Activator.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/QtUIPlugin.java similarity index 85% rename from qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/Activator.java rename to qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/QtUIPlugin.java index 5d1039b2ae0..d4b781e9e8b 100644 --- a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/Activator.java +++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/QtUIPlugin.java @@ -6,18 +6,18 @@ import org.osgi.framework.BundleContext; /** * The activator class controls the plug-in life cycle */ -public class Activator extends AbstractUIPlugin { +public class QtUIPlugin extends AbstractUIPlugin { // The plug-in ID public static final String PLUGIN_ID = "org.eclipse.cdt.qt.ui"; //$NON-NLS-1$ // The shared instance - private static Activator plugin; + private static QtUIPlugin plugin; /** * The constructor */ - public Activator() { + public QtUIPlugin() { } /* @@ -43,7 +43,7 @@ public class Activator extends AbstractUIPlugin { * * @return the shared instance */ - public static Activator getDefault() { + public static QtUIPlugin getDefault() { return plugin; }