mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-08 18:26:01 +02:00
Added checks to prevent insertion of duplicate 'using' declarations.
This commit is contained in:
parent
45c6b39f09
commit
78ff7d9795
3 changed files with 73 additions and 22 deletions
|
@ -27,8 +27,8 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
|
||||||
/**
|
/**
|
||||||
* @author jcamelon
|
* @author jcamelon
|
||||||
*/
|
*/
|
||||||
public class CPPASTUsingDeclaration extends ASTNode implements
|
public class CPPASTUsingDeclaration extends ASTNode
|
||||||
ICPPASTUsingDeclaration, IASTCompletionContext {
|
implements ICPPASTUsingDeclaration, IASTCompletionContext {
|
||||||
|
|
||||||
private boolean typeName;
|
private boolean typeName;
|
||||||
private IASTName name;
|
private IASTName name;
|
||||||
|
@ -70,19 +70,19 @@ public class CPPASTUsingDeclaration extends ASTNode implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept( ASTVisitor action ){
|
public boolean accept(ASTVisitor action) {
|
||||||
if( action.shouldVisitDeclarations ){
|
if (action.shouldVisitDeclarations) {
|
||||||
switch( action.visit( this ) ){
|
switch (action.visit(this)) {
|
||||||
case ASTVisitor.PROCESS_ABORT : return false;
|
case ASTVisitor.PROCESS_ABORT : return false;
|
||||||
case ASTVisitor.PROCESS_SKIP : return true;
|
case ASTVisitor.PROCESS_SKIP : return true;
|
||||||
default : break;
|
default : break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( name != null ) if( !name.accept( action ) ) return false;
|
if (name != null) if (!name.accept(action)) return false;
|
||||||
|
|
||||||
if( action.shouldVisitDeclarations ){
|
if (action.shouldVisitDeclarations) {
|
||||||
switch( action.leave( this ) ){
|
switch(action.leave(this)) {
|
||||||
case ASTVisitor.PROCESS_ABORT : return false;
|
case ASTVisitor.PROCESS_ABORT : return false;
|
||||||
case ASTVisitor.PROCESS_SKIP : return true;
|
case ASTVisitor.PROCESS_SKIP : return true;
|
||||||
default : break;
|
default : break;
|
||||||
|
@ -92,7 +92,7 @@ public class CPPASTUsingDeclaration extends ASTNode implements
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRoleForName(IASTName n) {
|
public int getRoleForName(IASTName n) {
|
||||||
if( n == name )
|
if (n == name)
|
||||||
return r_definition;
|
return r_definition;
|
||||||
return r_unclear;
|
return r_unclear;
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ public class CPPASTUsingDeclaration extends ASTNode implements
|
||||||
IBinding[] bindings = CPPSemantics.findBindingsForContentAssist(n, isPrefix);
|
IBinding[] bindings = CPPSemantics.findBindingsForContentAssist(n, isPrefix);
|
||||||
List<IBinding> filtered = new ArrayList<IBinding>();
|
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) {
|
if (bindings[i] instanceof ICPPNamespace) {
|
||||||
filtered.add(bindings[i]);
|
filtered.add(bindings[i]);
|
||||||
}
|
}
|
||||||
|
@ -109,4 +109,9 @@ public class CPPASTUsingDeclaration extends ASTNode implements
|
||||||
|
|
||||||
return filtered.toArray(new IBinding[filtered.size()]);
|
return filtered.toArray(new IBinding[filtered.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,4 +68,9 @@ public class CPPUsingDirective implements ICPPUsingDirective {
|
||||||
public IScope getContainingScope() {
|
public IScope getContainingScope() {
|
||||||
return CPPVisitor.getContainingScope(fNamespaceName);
|
return CPPVisitor.getContainingScope(fNamespaceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return fNamespaceName.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ import org.eclipse.ui.texteditor.TextEditorAction;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.CCorePlugin;
|
import org.eclipse.cdt.core.CCorePlugin;
|
||||||
import org.eclipse.cdt.core.dom.ast.DOMException;
|
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.IASTName;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTNodeSelector;
|
import org.eclipse.cdt.core.dom.ast.IASTNodeSelector;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
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.ICompositeType;
|
||||||
import org.eclipse.cdt.core.dom.ast.IEnumeration;
|
import org.eclipse.cdt.core.dom.ast.IEnumeration;
|
||||||
import org.eclipse.cdt.core.dom.ast.IFunction;
|
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.IType;
|
||||||
import org.eclipse.cdt.core.dom.ast.ITypedef;
|
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.ICPPBinding;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
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.ICPPNamespace;
|
||||||
|
@ -78,7 +81,6 @@ import org.eclipse.cdt.ui.text.ICHelpInvocationContext;
|
||||||
import org.eclipse.cdt.ui.text.SharedASTJob;
|
import org.eclipse.cdt.ui.text.SharedASTJob;
|
||||||
import org.eclipse.cdt.utils.PathUtil;
|
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.CPPVisitor;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
|
||||||
import org.eclipse.cdt.internal.core.resources.ResourceLookup;
|
import org.eclipse.cdt.internal.core.resources.ResourceLookup;
|
||||||
|
@ -212,8 +214,7 @@ public class AddIncludeOnSelectionAction extends TextEditorAction {
|
||||||
type = SemanticUtil.getNestedType(type,
|
type = SemanticUtil.getNestedType(type,
|
||||||
SemanticUtil.CVQ | SemanticUtil.PTR | SemanticUtil.ARRAY | SemanticUtil.REF);
|
SemanticUtil.CVQ | SemanticUtil.PTR | SemanticUtil.ARRAY | SemanticUtil.REF);
|
||||||
if (type instanceof IBinding) {
|
if (type instanceof IBinding) {
|
||||||
binding = (IBinding) type;
|
nameChars = ((IBinding) type).getNameCharArray();
|
||||||
nameChars = binding.getNameCharArray();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (DOMException e) {
|
} catch (DOMException e) {
|
||||||
|
@ -273,11 +274,8 @@ public class AddIncludeOnSelectionAction extends TextEditorAction {
|
||||||
IIndexBinding indexBinding = candidate.getBinding();
|
IIndexBinding indexBinding = candidate.getBinding();
|
||||||
|
|
||||||
if (indexBinding instanceof ICPPBinding && !(indexBinding instanceof IIndexMacro)) {
|
if (indexBinding instanceof ICPPBinding && !(indexBinding instanceof IIndexMacro)) {
|
||||||
// Decide what 'using' declaration should be added along with the include.
|
// Decide what 'using' declaration, if any, should be added along with the include.
|
||||||
if (binding == null) {
|
String usingDeclaration = deduceUsingDeclaration(binding, indexBinding, ast);
|
||||||
binding = new ProblemBinding(name, IProblemBinding.SEMANTIC_NAME_NOT_FOUND);
|
|
||||||
}
|
|
||||||
String usingDeclaration = deduceUsingDeclaration(binding, indexBinding);
|
|
||||||
if (usingDeclaration != null)
|
if (usingDeclaration != null)
|
||||||
fUsingDeclarations = new String[] { usingDeclaration };
|
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)) {
|
if (source.equals(target)) {
|
||||||
return null; // No using declaration is needed.
|
return null; // No using declaration is needed.
|
||||||
}
|
}
|
||||||
|
@ -311,6 +309,27 @@ public class AddIncludeOnSelectionAction extends TextEditorAction {
|
||||||
if (targetChain.size() <= 1) {
|
if (targetChain.size() <= 1) {
|
||||||
return null; // Target is not in a namespace
|
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);
|
ArrayList<String> sourceChain = getUsingChain(source);
|
||||||
if (sourceChain.size() >= targetChain.size()) {
|
if (sourceChain.size() >= targetChain.size()) {
|
||||||
int j = targetChain.size();
|
int j = targetChain.size();
|
||||||
|
@ -333,6 +352,28 @@ public class AddIncludeOnSelectionAction extends TextEditorAction {
|
||||||
return buf.toString();
|
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) {
|
private ArrayList<String> getUsingChain(IBinding binding) {
|
||||||
ArrayList<String> chain = new ArrayList<String>(4);
|
ArrayList<String> chain = new ArrayList<String>(4);
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Add table
Reference in a new issue