mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-15 04:55:22 +02:00
Bug 485388 - Ambiguity resolution of method bodies of nested classes
They can depend on members of enclosing classes, so their processing needs to wait until the end of the outermost class definition. Change-Id: Ie714d8410bb7a474bcc8dfab0bc09fcc89450598 Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
This commit is contained in:
parent
082dae21c3
commit
3d814869df
2 changed files with 55 additions and 45 deletions
|
@ -8955,6 +8955,23 @@ public class AST2TemplateTests extends AST2TestBase {
|
||||||
parseAndCheckBindings();
|
parseAndCheckBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// template <typename> struct S {};
|
||||||
|
// struct U {};
|
||||||
|
//
|
||||||
|
// struct outer {
|
||||||
|
// struct inner {
|
||||||
|
// S<U> foo() {
|
||||||
|
// return waldo<42>(0);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// template <int>
|
||||||
|
// static S<U> waldo(int);
|
||||||
|
// };
|
||||||
|
public void testAmbiguityResolutionInNestedClassMethodBody_485388() throws Exception {
|
||||||
|
parseAndCheckBindings();
|
||||||
|
}
|
||||||
|
|
||||||
// template <typename>
|
// template <typename>
|
||||||
// struct Base {
|
// struct Base {
|
||||||
// template <typename>
|
// template <typename>
|
||||||
|
|
|
@ -14,7 +14,6 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
|
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
|
||||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||||
|
@ -48,9 +47,18 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
||||||
*/
|
*/
|
||||||
final class CPPASTAmbiguityResolver extends ASTVisitor {
|
final class CPPASTAmbiguityResolver extends ASTVisitor {
|
||||||
private int fSkipInitializers= 0;
|
private int fSkipInitializers= 0;
|
||||||
private int fDeferFunctions= 1;
|
/*
|
||||||
|
* The current nesting level of class definitions.
|
||||||
|
* Used to handle processing of method bodies, which are deferred
|
||||||
|
* until the end of the outermost class definition.
|
||||||
|
*/
|
||||||
|
private int fClassNestingLevel= 0;
|
||||||
private HashSet<IASTDeclaration> fRepopulate= new HashSet<>();
|
private HashSet<IASTDeclaration> fRepopulate= new HashSet<>();
|
||||||
private Deque<Deque<IASTNode>> fDeferredNodes= new ArrayDeque<>();
|
/*
|
||||||
|
* Nodes that have been deferred for later processing.
|
||||||
|
* Currently used only for method bodies.
|
||||||
|
*/
|
||||||
|
private Deque<IASTNode> fDeferredNodes = new ArrayDeque<>();
|
||||||
|
|
||||||
public CPPASTAmbiguityResolver() {
|
public CPPASTAmbiguityResolver() {
|
||||||
super(false);
|
super(false);
|
||||||
|
@ -98,8 +106,7 @@ final class CPPASTAmbiguityResolver extends ASTVisitor {
|
||||||
@Override
|
@Override
|
||||||
public int visit(IASTDeclSpecifier declSpec) {
|
public int visit(IASTDeclSpecifier declSpec) {
|
||||||
if (declSpec instanceof ICPPASTCompositeTypeSpecifier) {
|
if (declSpec instanceof ICPPASTCompositeTypeSpecifier) {
|
||||||
fDeferFunctions++;
|
fClassNestingLevel++;
|
||||||
fDeferredNodes.add(new ArrayDeque<IASTNode>());
|
|
||||||
}
|
}
|
||||||
return PROCESS_CONTINUE;
|
return PROCESS_CONTINUE;
|
||||||
}
|
}
|
||||||
|
@ -107,7 +114,7 @@ final class CPPASTAmbiguityResolver extends ASTVisitor {
|
||||||
@Override
|
@Override
|
||||||
public int leave(IASTDeclSpecifier declSpec) {
|
public int leave(IASTDeclSpecifier declSpec) {
|
||||||
if (declSpec instanceof ICPPASTCompositeTypeSpecifier) {
|
if (declSpec instanceof ICPPASTCompositeTypeSpecifier) {
|
||||||
fDeferFunctions--;
|
fClassNestingLevel--;
|
||||||
|
|
||||||
// Resolve class type definitions, such that the scope is available
|
// Resolve class type definitions, such that the scope is available
|
||||||
// during ambiguity resolution.
|
// during ambiguity resolution.
|
||||||
|
@ -117,14 +124,20 @@ final class CPPASTAmbiguityResolver extends ASTVisitor {
|
||||||
if (declSpec instanceof CPPASTCompositeTypeSpecifier)
|
if (declSpec instanceof CPPASTCompositeTypeSpecifier)
|
||||||
((CPPASTCompositeTypeSpecifier) declSpec).setAmbiguitiesResolved();
|
((CPPASTCompositeTypeSpecifier) declSpec).setAmbiguitiesResolved();
|
||||||
|
|
||||||
processDeferredNodes(fDeferredNodes.removeLast());
|
// If we are leaving the outermost class, process the bodies of
|
||||||
|
// methods of the class and its nested classes.
|
||||||
|
if (fClassNestingLevel == 0) {
|
||||||
|
while (!fDeferredNodes.isEmpty()) {
|
||||||
|
fDeferredNodes.removeFirst().accept(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return PROCESS_CONTINUE;
|
return PROCESS_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int visit(IASTDeclaration decl) {
|
public int visit(IASTDeclaration decl) {
|
||||||
if (fDeferFunctions > 0 && decl instanceof IASTFunctionDefinition) {
|
if (fClassNestingLevel > 0 && decl instanceof IASTFunctionDefinition) {
|
||||||
final IASTFunctionDefinition fdef= (IASTFunctionDefinition) decl;
|
final IASTFunctionDefinition fdef= (IASTFunctionDefinition) decl;
|
||||||
|
|
||||||
// Visit the declarator first, it may contain ambiguous template arguments needed
|
// Visit the declarator first, it may contain ambiguous template arguments needed
|
||||||
|
@ -140,7 +153,7 @@ final class CPPASTAmbiguityResolver extends ASTVisitor {
|
||||||
trailingReturnType.accept(this);
|
trailingReturnType.accept(this);
|
||||||
}
|
}
|
||||||
// Defer visiting the body of the function until the class body has been visited.
|
// Defer visiting the body of the function until the class body has been visited.
|
||||||
fDeferredNodes.getLast().add(decl);
|
fDeferredNodes.add(decl);
|
||||||
return PROCESS_SKIP;
|
return PROCESS_SKIP;
|
||||||
}
|
}
|
||||||
return PROCESS_CONTINUE;
|
return PROCESS_CONTINUE;
|
||||||
|
@ -187,33 +200,15 @@ final class CPPASTAmbiguityResolver extends ASTVisitor {
|
||||||
return PROCESS_CONTINUE;
|
return PROCESS_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int visit(IASTTranslationUnit tu) {
|
|
||||||
fDeferredNodes.add(new ArrayDeque<IASTNode>());
|
|
||||||
return PROCESS_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int leave(IASTTranslationUnit tu) {
|
public int leave(IASTTranslationUnit tu) {
|
||||||
fDeferFunctions= 0;
|
// As deferred method bodies are processed at the end of outermost
|
||||||
while (!fDeferredNodes.isEmpty()) {
|
// class definitions, there should be none left when the end of
|
||||||
processDeferredNodes(fDeferredNodes.removeLast());
|
// the translation unit is reached.
|
||||||
}
|
assert fDeferredNodes.isEmpty();
|
||||||
return PROCESS_CONTINUE;
|
return PROCESS_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processDeferredNodes(Deque<IASTNode> deferredNodes) {
|
|
||||||
int deferFunctions = fDeferFunctions;
|
|
||||||
fDeferFunctions = 0;
|
|
||||||
try {
|
|
||||||
while (!deferredNodes.isEmpty()) {
|
|
||||||
deferredNodes.removeFirst().accept(this);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
fDeferFunctions = deferFunctions;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void repopulateScope(IASTDeclaration declaration) {
|
private void repopulateScope(IASTDeclaration declaration) {
|
||||||
IScope scope= CPPVisitor.getContainingNonTemplateScope(declaration);
|
IScope scope= CPPVisitor.getContainingNonTemplateScope(declaration);
|
||||||
if (scope instanceof ICPPASTInternalScope) {
|
if (scope instanceof ICPPASTInternalScope) {
|
||||||
|
@ -232,21 +227,19 @@ final class CPPASTAmbiguityResolver extends ASTVisitor {
|
||||||
* If 'node' has been deferred for later processing, process it now.
|
* If 'node' has been deferred for later processing, process it now.
|
||||||
*/
|
*/
|
||||||
public void resolvePendingAmbiguities(IASTNode node) {
|
public void resolvePendingAmbiguities(IASTNode node) {
|
||||||
Iterator<Deque<IASTNode>> iterator = fDeferredNodes.descendingIterator();
|
for (IASTNode deferredNode : fDeferredNodes) {
|
||||||
while (iterator.hasNext()) {
|
if (deferredNode == node) {
|
||||||
Deque<IASTNode> deferred = iterator.next();
|
// Temporarily set the class nesting level to 0,
|
||||||
for (IASTNode deferredNode : deferred) {
|
// to prevent the node just being deferred again.
|
||||||
if (deferredNode == node) {
|
int classNestingLevel = fClassNestingLevel;
|
||||||
int deferFunctions = fDeferFunctions;
|
fClassNestingLevel = 0;
|
||||||
fDeferFunctions = 0;
|
try {
|
||||||
try {
|
deferredNode.accept(this);
|
||||||
deferredNode.accept(this);
|
} finally {
|
||||||
} finally {
|
fClassNestingLevel = classNestingLevel;
|
||||||
fDeferFunctions = deferFunctions;
|
|
||||||
}
|
|
||||||
deferred.remove(deferredNode);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
fDeferredNodes.remove(deferredNode);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue