From 6fb068d42ef9a728ac2a9ba4cfd76f618375e2f8 Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Fri, 26 Feb 2016 16:32:21 -0800 Subject: [PATCH] Bug 488604 - Organize Includes adds include for type hidden behind a macro Change-Id: Ibfe1499580b3b34ff9c3cff0fbbd8b3b3b9506fa --- .../includes/BindingClassifierTest.java | 46 +++++++ .../includes/BindingClassifier.java | 119 +++++++++++------- 2 files changed, 123 insertions(+), 42 deletions(-) diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/BindingClassifierTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/BindingClassifierTest.java index 3b79c244d64..7856214bbeb 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/BindingClassifierTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/BindingClassifierTest.java @@ -387,6 +387,38 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase { assertDeclared(); } + // class A {}; + // class B {}; + // class C {}; + // class D {}; + + // void foo(A* a, B& b, C& c) { + // A& aa(*a); + // B* bb(&b); + // C cc(c); + // D d; + // } + public void testVariableDeclaration() throws Exception { + assertDefined("C", "D"); + assertDeclared("A", "B"); + } + + // class A {}; + // class B {}; + // class C {}; + + // class D { + // A* aa; + // B& bb; + // C cc; + // D(A* a, B& b, C& c) + // : aa(a), bb(b), cc(c) {} + // }; + public void testConstructorChainInitializer() throws Exception { + assertDefined("C"); + assertDeclared("A", "B"); + } + // namespace ns1 { // namespace ns2 { // class A {}; @@ -758,6 +790,20 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase { assertDeclared(); } + // struct A { + // A(int); + // }; + // + // #define MACRO(a, b) A a(b) + + // void test(int x) { + // MACRO(a, x); + // } + public void testMacro_6() throws Exception { + assertDefined("MACRO"); + assertDeclared(); + } + // #define bool bool // #define false false diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java index e1009e2b0e9..16aa93e922e 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java @@ -59,6 +59,7 @@ import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; +import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorFunctionStyleMacroDefinition; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; @@ -127,9 +128,11 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClosureType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper.MethodKind; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.LookupData; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; @@ -351,23 +354,23 @@ public class BindingClassifier { */ // Get the binding of the initialized AST name first. - IASTNode memberNode = initializer; - IASTName memberName = null; - IBinding memberBinding = null; + IASTNode variableNode = initializer; + IASTName variableName = null; + IBinding variableBinding = null; - while (memberNode != null) { - if (memberNode instanceof IASTDeclarator) { - memberName = ((IASTDeclarator) memberNode).getName(); + while (variableNode != null) { + if (variableNode instanceof IASTDeclarator) { + variableName = ((IASTDeclarator) variableNode).getName(); break; - } else if (memberNode instanceof ICPPASTConstructorChainInitializer) { - memberName = ((ICPPASTConstructorChainInitializer) memberNode).getMemberInitializerId(); + } else if (variableNode instanceof ICPPASTConstructorChainInitializer) { + variableName = ((ICPPASTConstructorChainInitializer) variableNode).getMemberInitializerId(); break; } - memberNode = memberNode.getParent(); + variableNode = variableNode.getParent(); } - if (memberName != null) - memberBinding = memberName.resolveBinding(); + if (variableName != null) + variableBinding = variableName.resolveBinding(); // Get the arguments of the initializer. IASTInitializerClause[] arguments = IASTExpression.EMPTY_EXPRESSION_ARRAY; @@ -379,13 +382,22 @@ public class BindingClassifier { arguments = new IASTInitializerClause[] { equalsInitializer.getInitializerClause() }; } - if (memberBinding instanceof IVariable) { + if (variableBinding instanceof IVariable) { // Variable construction. - IType memberType = ((IVariable) memberBinding).getType(); - if (!(memberType instanceof IPointerType || memberType instanceof ICPPReferenceType)) { - // We're constructing a non-pointer type. We need to define the member type - // either way since we must be able to call its constructor. - defineTypeExceptTypedefOrNonFixedEnum(memberType); + boolean defineVariableType = true; + if (initializer.getPropertyInParent() == IASTDeclarator.INITIALIZER) { + IASTDeclarator declarator = (IASTDeclarator) initializer.getParent(); + IASTDeclSpecifier declSpec = getDeclarationSpecifier(declarator); + if (declSpec != null && isPartOfExternalMacroDefinition(declSpec)) + defineVariableType = false; + } + IType targetType = ((IVariable) variableBinding).getType(); + if (!(targetType instanceof IPointerType || targetType instanceof ICPPReferenceType)) { + if (defineVariableType) { + // We're constructing a non-pointer type. We need to define the member type + // either way since we must be able to call its constructor. + defineTypeExceptTypedefOrNonFixedEnum(targetType); + } // TODO: Process the arguments. But how to get the corresponding IParameter[] array here? // processParameters(declaredParameters, arguments); @@ -394,24 +406,22 @@ public class BindingClassifier { // to check whether the argument type matches the declared type. for (IASTInitializerClause argument : arguments) { if (argument instanceof IASTExpression) { - IType argumentType = ((IASTExpression) argument).getExpressionType(); - if (isTypeDefinitionRequiredForConversion(argumentType, memberType)) { + IASTExpression expression = (IASTExpression) argument; + IType argumentType = expression.getExpressionType(); + if (targetType instanceof ICPPReferenceType + && expression instanceof IASTUnaryExpression + && ((IASTUnaryExpression) expression).getOperator() == IASTUnaryExpression.op_star) { + argumentType = new CPPReferenceType(argumentType, false); + } + if (isTypeDefinitionRequiredForConversion(argumentType, targetType)) { // Types don't match. Define both types. - defineTypeExceptTypedefOrNonFixedEnum(memberType); + if (defineVariableType) + defineTypeExceptTypedefOrNonFixedEnum(targetType); defineTypeExceptTypedefOrNonFixedEnum(argumentType); } } } } - } else if (memberBinding instanceof ICPPConstructor) { - // Class construction. - ICPPConstructor constructor = (ICPPConstructor) memberBinding; - - // We need to define the owning type of the constructor. - defineBinding(constructor.getOwner()); - - // Process the parameters. - processFunctionParameters(constructor, true, arguments); } return PROCESS_CONTINUE; } @@ -568,20 +578,25 @@ public class BindingClassifier { boolean expressionDefinitionRequired = true; switch (unaryExpression.getOperator()) { - case IASTUnaryExpression.op_amper: - case IASTUnaryExpression.op_bracketedPrimary: - // The ampersand operator as well as brackets never require a definition. - expressionDefinitionRequired = false; + case IASTUnaryExpression.op_amper: + case IASTUnaryExpression.op_bracketedPrimary: + // The ampersand operator as well as brackets never require a definition. + expressionDefinitionRequired = false; + break; + case IASTUnaryExpression.op_star: + if (expression.getParent() instanceof IASTExpression) break; - case IASTUnaryExpression.op_alignOf: - case IASTUnaryExpression.op_not: - case IASTUnaryExpression.op_plus: - case IASTUnaryExpression.op_sizeof: - case IASTUnaryExpression.op_typeid: - // If the operand is a pointer type, then it doesn't need to be defined. - if (operand.getExpressionType() instanceof IPointerType) { - expressionDefinitionRequired = false; - } + //$FALL-THROUGH$ + case IASTUnaryExpression.op_alignOf: + case IASTUnaryExpression.op_not: + case IASTUnaryExpression.op_plus: + case IASTUnaryExpression.op_sizeof: + case IASTUnaryExpression.op_typeid: + // If the operand is a pointer type, then it doesn't need to be defined. + if (operand.getExpressionType() instanceof IPointerType) { + expressionDefinitionRequired = false; + } + break; } if (expressionDefinitionRequired) { @@ -1568,4 +1583,24 @@ public class BindingClassifier { node.accept(localNameFinder); return localNameFinder.found; } + + /** + * Returns the declaration specifier node for the given declarator. + */ + private static IASTDeclSpecifier getDeclarationSpecifier(IASTDeclarator declarator) { + declarator= CPPVisitor.findOutermostDeclarator(declarator); + IASTNode parent = declarator.getParent(); + + IASTDeclSpecifier declSpec = null; + if (parent instanceof IASTSimpleDeclaration) { + declSpec = ((IASTSimpleDeclaration) parent).getDeclSpecifier(); + } else if (parent instanceof IASTParameterDeclaration) { + declSpec = ((IASTParameterDeclaration) parent).getDeclSpecifier(); + } else if (parent instanceof IASTFunctionDefinition) { + declSpec = ((IASTFunctionDefinition) parent).getDeclSpecifier(); + } else if (parent instanceof ICPPASTTypeId) { + declSpec = ((ICPPASTTypeId) parent).getDeclSpecifier(); + } + return declSpec; + } }