1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 14:42:11 +02:00

Bug 45203. Produce include staements for macros. Don't generate include

statements for types brought in by macro expansion.
This commit is contained in:
Sergey Prigogin 2013-07-29 14:20:36 -07:00
parent 89ba6685cb
commit b603ca080d
5 changed files with 149 additions and 61 deletions

View file

@ -68,12 +68,16 @@ public class OneSourceMultipleHeadersTestCase extends BaseTestCase {
return ast;
}
public String getAstSource() {
protected String getAstSource() {
return testData[testData.length - 1].toString();
}
@Override
protected void setUp() throws Exception {
setUp(false);
}
protected void setUp(boolean generateIncludeStatements) throws Exception {
cproject = cpp ?
CProjectHelper.createCCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER) :
CProjectHelper.createCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER);
@ -87,6 +91,15 @@ public class OneSourceMultipleHeadersTestCase extends BaseTestCase {
}
}
if (generateIncludeStatements) {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < getTestData().length - 1; i++) {
String filename = String.format("header%d.h", i + 1);
buf.append(String.format("#include \"header%d.h\"\n", i + 1));
}
testData[testData.length - 1].insert(0, buf);
}
IFile cppfile= TestSourceReader.createFile(cproject.getProject(), new Path("source.c" + (cpp ? "pp" : "")), getAstSource());
waitForIndexer(cproject);

View file

@ -11,6 +11,7 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Semaphore;
@ -149,7 +150,18 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat
protected final IASTName[] getMacroDefinitionsInAST(IMacroBinding binding) {
if (fLocationResolver == null)
return IASTName.EMPTY_NAME_ARRAY;
return fLocationResolver.getDeclarations(binding);
IASTName[] declarations = fLocationResolver.getDeclarations(binding);
int j = 0;
for (int i = 0; i < declarations.length; i++) {
IASTName name = declarations[i];
if (name.isPartOfTranslationUnitFile()) {
declarations[j++] = name;
}
}
if (j < declarations.length)
return j > 0 ? Arrays.copyOf(declarations, j) : IASTName.EMPTY_NAME_ARRAY;
return declarations;
}
protected final IASTName[] getMacroReferencesInAST(IMacroBinding binding) {

View file

@ -104,10 +104,11 @@ class LocationCtxFile extends LocationCtxContainer {
}
public boolean isThisFile(int sequenceNumber) {
if (sequenceNumber < 0)
return false;
LocationCtx child= findChildLessOrEqualThan(sequenceNumber, false);
if (!(child instanceof LocationCtxFile)) {
if (!(child instanceof LocationCtxFile))
return true;
}
return sequenceNumber >= child.fSequenceNumber + child.getSequenceLength();
}

View file

@ -51,7 +51,7 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
super.setUp(true);
IASTTranslationUnit ast = getAst();
fIndex = CCorePlugin.getIndexManager().getIndex(getCProject(),
IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_EXTENSION_FRAGMENTS_ADD_IMPORT);
@ -223,4 +223,16 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
assertDefined("D");
assertDeclared();
}
// struct A {};
// struct B {};
// struct C {};
// struct prefixD {};
// #define MACRO(t1, v1, t2, v3, t4, v4) t1 v1; t2 b; C v3; prefix##t4 v4
// MACRO(A, a, B, c, D, d);
public void testMacro() throws Exception {
assertDefined("A", "B", "MACRO");
assertDeclared();
}
}

View file

@ -44,14 +44,18 @@ import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTImageLocation;
import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation;
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.IASTPointerOperator;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
@ -186,28 +190,6 @@ public class BindingClassifier {
}
}
/**
* Returns whether the two given types are identical. This does the same as IType.isSameType()
* with the exception that it considers a pointer and the zero literal identical.
*/
private boolean isSameType(IType type1, IType type2) {
if (type1 == null || type2 == null) {
return false;
}
if (type1.isSameType(type2)) {
return true;
}
if (type1 instanceof IPointerType || type2 instanceof IPointerType) {
if ((type1 instanceof IBasicType && ((IBasicType) type1).getKind() == Kind.eInt)
|| (type2 instanceof IBasicType && ((IBasicType) type2).getKind() == Kind.eInt)) {
return true;
}
}
return false;
}
/**
* Resolves the given binding and returns the binding(s) which we actually have to either
* declare or define. As an example, if the given binding is a variable, this function returns
@ -277,24 +259,6 @@ public class BindingClassifier {
return bindings;
}
/**
* Resolves the given type to a binding which we actually have to either declare or define.
* As an example if the given type is a pointer type, this function returns the binding for
* the raw (i.e. nested) type of the pointer. This is because we actually have to declare or
* define the raw type of a pointer, not the pointer type itself.
*
* @param type The type to resolve.
* @return A binding which is suitable for either declaration or definition, or {@code null}
* if no such binding is available.
*/
private IBinding getTypeBinding(IType type) {
type = getNestedType(type, ALLCVQ | PTR | ARRAY | REF);
if (type instanceof IBinding) {
return (IBinding) type;
}
return null;
}
/**
* Adds the given binding to the list of bindings which have to be forward declared.
*
@ -380,29 +344,15 @@ public class BindingClassifier {
}
}
private boolean isEnumerationWithoutFixedUnderlyingType(IBinding typeBinding) {
return typeBinding instanceof IEnumeration
&& (!(typeBinding instanceof ICPPEnumeration) || ((ICPPEnumeration) typeBinding).getFixedType() == null);
}
/**
* Adds the given binding to the list of bindings which have to be defined.
*
* @param binding The binding to add.
*/
private void defineBinding(IBinding binding) {
if (!fProcessedDefinedBindings.add(binding))
if (!markAsDefined(binding))
return;
if (binding instanceof ITypedef) {
IType type = ((ITypedef) binding).getType();
type = SemanticUtil.getNestedType(type, ALLCVQ);
if (type instanceof IBinding) {
// Record the fact that we also have a definition of the typedef's target type.
fProcessedDefinedBindings.add((IBinding) type);
}
}
if (fAst.getDefinitionsInAST(binding).length != 0) {
return; // Defined locally
}
@ -414,6 +364,29 @@ public class BindingClassifier {
}
}
/**
* Marks the given binding as defined.
*
* @param binding the binding to mark
* @return {{@code true} if the binding has not yet been marked as defined,
* {@code false} otherwise.
*/
private boolean markAsDefined(IBinding binding) {
if (!fProcessedDefinedBindings.add(binding))
return false;
if (binding instanceof ITypedef) {
IType type = ((ITypedef) binding).getType();
type = SemanticUtil.getNestedType(type, ALLCVQ);
if (type instanceof IBinding) {
// Record the fact that we also have a definition of the typedef's target type.
fProcessedDefinedBindings.add((IBinding) type);
}
}
return true;
}
private void declareFunction(IFunction function, IASTFunctionCallExpression functionCallExpression) {
// Handle return or expression type of the function or constructor call.
IType returnType = function.getType().getReturnType();
@ -483,7 +456,13 @@ public class BindingClassifier {
}
if (!canBeDeclared) {
defineBinding(((IASTNamedTypeSpecifier) declSpecifier).getName().resolveBinding());
IASTName name = ((IASTNamedTypeSpecifier) declSpecifier).getName();
IBinding binding = name.resolveBinding();
if (isPartOfExternalMacroDefinition(name)) {
markAsDefined(binding);
} else {
defineBinding(binding);
}
}
}
} else if (declaration instanceof IASTFunctionDefinition) {
@ -1016,5 +995,76 @@ public class BindingClassifier {
}
return PROCESS_CONTINUE;
}
@Override
public int visit(IASTTranslationUnit tu) {
for (IASTPreprocessorMacroExpansion macroExpansion : tu.getMacroExpansions()) {
IBinding binding = macroExpansion.getMacroReference().getBinding();
defineBinding(binding);
}
return PROCESS_CONTINUE;
}
}
/**
* Returns whether the two given types are identical. This does the same as IType.isSameType()
* with the exception that it considers a pointer and the zero literal identical.
*/
private static boolean isSameType(IType type1, IType type2) {
if (type1 == null || type2 == null) {
return false;
}
if (type1.isSameType(type2)) {
return true;
}
if (type1 instanceof IPointerType || type2 instanceof IPointerType) {
if ((type1 instanceof IBasicType && ((IBasicType) type1).getKind() == Kind.eInt)
|| (type2 instanceof IBasicType && ((IBasicType) type2).getKind() == Kind.eInt)) {
return true;
}
}
return false;
}
/**
* Resolves the given type to a binding which we actually have to either declare or define.
* As an example if the given type is a pointer type, this function returns the binding for
* the raw (i.e. nested) type of the pointer. This is because we actually have to declare or
* define the raw type of a pointer, not the pointer type itself.
*
* @param type The type to resolve.
* @return A binding which is suitable for either declaration or definition, or {@code null}
* if no such binding is available.
*/
private static IBinding getTypeBinding(IType type) {
type = getNestedType(type, ALLCVQ | PTR | ARRAY | REF);
if (type instanceof IBinding) {
return (IBinding) type;
}
return null;
}
private static boolean isEnumerationWithoutFixedUnderlyingType(IBinding typeBinding) {
return typeBinding instanceof IEnumeration
&& (!(typeBinding instanceof ICPPEnumeration) || ((ICPPEnumeration) typeBinding).getFixedType() == null);
}
private static boolean isPartOfExternalMacroDefinition(IASTName name) {
IASTNodeLocation[] locations = name.getNodeLocations();
if (locations.length != 1 || !(locations[0] instanceof IASTMacroExpansionLocation))
return false;
IASTMacroExpansionLocation macroExpansionLocation = (IASTMacroExpansionLocation) locations[0];
IASTPreprocessorMacroExpansion macroExpansion = macroExpansionLocation.getExpansion();
if (macroExpansion.getMacroDefinition().isPartOfTranslationUnitFile())
return false;
IASTImageLocation imageLocation = name.getImageLocation();
if (imageLocation != null &&
imageLocation.getFileName().equals(name.getTranslationUnit().getFilePath())) {
return false;
}
return true;
}
}