1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-08 10:16:03 +02:00

Added checks to prevent insertion of duplicate 'using' declarations.

This commit is contained in:
Sergey Prigogin 2009-05-09 00:14:18 +00:00
parent 45c6b39f09
commit 78ff7d9795
3 changed files with 73 additions and 22 deletions

View file

@ -27,8 +27,8 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
/**
* @author jcamelon
*/
public class CPPASTUsingDeclaration extends ASTNode implements
ICPPASTUsingDeclaration, IASTCompletionContext {
public class CPPASTUsingDeclaration extends ASTNode
implements ICPPASTUsingDeclaration, IASTCompletionContext {
private boolean typeName;
private IASTName name;
@ -70,19 +70,19 @@ public class CPPASTUsingDeclaration extends ASTNode implements
}
@Override
public boolean accept( ASTVisitor action ){
if( action.shouldVisitDeclarations ){
switch( action.visit( this ) ){
public boolean accept(ASTVisitor action) {
if (action.shouldVisitDeclarations) {
switch (action.visit(this)) {
case ASTVisitor.PROCESS_ABORT : return false;
case ASTVisitor.PROCESS_SKIP : return true;
default : break;
}
}
if( name != null ) if( !name.accept( action ) ) return false;
if (name != null) if (!name.accept(action)) return false;
if( action.shouldVisitDeclarations ){
switch( action.leave( this ) ){
if (action.shouldVisitDeclarations) {
switch(action.leave(this)) {
case ASTVisitor.PROCESS_ABORT : return false;
case ASTVisitor.PROCESS_SKIP : return true;
default : break;
@ -92,7 +92,7 @@ public class CPPASTUsingDeclaration extends ASTNode implements
}
public int getRoleForName(IASTName n) {
if( n == name )
if (n == name)
return r_definition;
return r_unclear;
}
@ -101,7 +101,7 @@ public class CPPASTUsingDeclaration extends ASTNode implements
IBinding[] bindings = CPPSemantics.findBindingsForContentAssist(n, isPrefix);
List<IBinding> filtered = new ArrayList<IBinding>();
for (int i = 0;i < bindings.length; i++) {
for (int i = 0; i < bindings.length; i++) {
if (bindings[i] instanceof ICPPNamespace) {
filtered.add(bindings[i]);
}
@ -109,4 +109,9 @@ public class CPPASTUsingDeclaration extends ASTNode implements
return filtered.toArray(new IBinding[filtered.size()]);
}
@Override
public String toString() {
return name.toString();
}
}

View file

@ -68,4 +68,9 @@ public class CPPUsingDirective implements ICPPUsingDirective {
public IScope getContainingScope() {
return CPPVisitor.getContainingScope(fNamespaceName);
}
@Override
public String toString() {
return fNamespaceName.toString();
}
}

View file

@ -46,6 +46,7 @@ import org.eclipse.ui.texteditor.TextEditorAction;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNodeSelector;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
@ -53,9 +54,11 @@ 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.IFunction;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef;
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.ICPPBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace;
@ -78,7 +81,6 @@ import org.eclipse.cdt.ui.text.ICHelpInvocationContext;
import org.eclipse.cdt.ui.text.SharedASTJob;
import org.eclipse.cdt.utils.PathUtil;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
import org.eclipse.cdt.internal.core.resources.ResourceLookup;
@ -111,8 +113,8 @@ public class AddIncludeOnSelectionAction extends TextEditorAction {
AddIncludesOperation op= new AddIncludesOperation(fTu, includes, usings, false);
try {
PlatformUI.getWorkbench().getProgressService().runInUI(
PlatformUI.getWorkbench().getProgressService(),
new WorkbenchRunnableAdapter(op), op.getSchedulingRule());
PlatformUI.getWorkbench().getProgressService(),
new WorkbenchRunnableAdapter(op), op.getSchedulingRule());
} catch (InvocationTargetException e) {
ExceptionHandler.handle(e, getShell(), CEditorMessages.AddIncludeOnSelection_error_title,
CEditorMessages.AddIncludeOnSelection_insertion_failed);
@ -212,8 +214,7 @@ public class AddIncludeOnSelectionAction extends TextEditorAction {
type = SemanticUtil.getNestedType(type,
SemanticUtil.CVQ | SemanticUtil.PTR | SemanticUtil.ARRAY | SemanticUtil.REF);
if (type instanceof IBinding) {
binding = (IBinding) type;
nameChars = binding.getNameCharArray();
nameChars = ((IBinding) type).getNameCharArray();
}
}
} catch (DOMException e) {
@ -273,11 +274,8 @@ public class AddIncludeOnSelectionAction extends TextEditorAction {
IIndexBinding indexBinding = candidate.getBinding();
if (indexBinding instanceof ICPPBinding && !(indexBinding instanceof IIndexMacro)) {
// Decide what 'using' declaration should be added along with the include.
if (binding == null) {
binding = new ProblemBinding(name, IProblemBinding.SEMANTIC_NAME_NOT_FOUND);
}
String usingDeclaration = deduceUsingDeclaration(binding, indexBinding);
// Decide what 'using' declaration, if any, should be added along with the include.
String usingDeclaration = deduceUsingDeclaration(binding, indexBinding, ast);
if (usingDeclaration != null)
fUsingDeclarations = new String[] { usingDeclaration };
}
@ -303,7 +301,7 @@ public class AddIncludeOnSelectionAction extends TextEditorAction {
}
}
private String deduceUsingDeclaration(IBinding source, IBinding target) {
private String deduceUsingDeclaration(IBinding source, IBinding target, IASTTranslationUnit ast) {
if (source.equals(target)) {
return null; // No using declaration is needed.
}
@ -311,6 +309,27 @@ public class AddIncludeOnSelectionAction extends TextEditorAction {
if (targetChain.size() <= 1) {
return null; // Target is not in a namespace
}
// Check if any of the existing using declarations and directives matches
// the target.
final IASTDeclaration[] declarations= ast.getDeclarations(false);
for (IASTDeclaration declaration : declarations) {
if (declaration.isPartOfTranslationUnitFile()) {
IASTName name = null;
if (declaration instanceof ICPPASTUsingDeclaration) {
name = ((ICPPASTUsingDeclaration) declaration).getName();
if (match(name, targetChain, false)) {
return null;
}
} else if (declaration instanceof ICPPASTUsingDirective) {
name = ((ICPPASTUsingDirective) declaration).getQualifiedName();
if (match(name, targetChain, true)) {
return null;
}
}
}
}
ArrayList<String> sourceChain = getUsingChain(source);
if (sourceChain.size() >= targetChain.size()) {
int j = targetChain.size();
@ -333,6 +352,28 @@ public class AddIncludeOnSelectionAction extends TextEditorAction {
return buf.toString();
}
private boolean match(IASTName name, ArrayList<String> usingChain, boolean excludeLast) {
IASTName[] names;
if (name instanceof ICPPASTQualifiedName) {
names = ((ICPPASTQualifiedName) name).getNames();
} else {
names = new IASTName[] { name };
}
if (names.length != usingChain.size() - (excludeLast ? 1 : 0)) {
return false;
}
for (int i = 0; i < names.length; i++) {
if (!names[i].toString().equals(usingChain.get(usingChain.size() - 1 - i))) {
return false;
}
}
return true;
}
/**
* Returns components of the qualified name in reverse order.
* For ns1::ns2::Name, e.g., it returns [Name, ns2, ns1].
*/
private ArrayList<String> getUsingChain(IBinding binding) {
ArrayList<String> chain = new ArrayList<String>(4);
try {